AWS Lambda Testing Guide
========================
.. note::
**Problem-solving guide for AWS Lambda testing with HoneyHive SDK**
Comprehensive solutions for testing HoneyHive SDK in AWS Lambda environments, from local development to production validation.
AWS Lambda presents unique challenges for observability SDKs. This guide provides tested solutions for validating HoneyHive SDK performance and functionality in serverless environments.
Quick Start
-----------
**Problem**: I need to test my HoneyHive integration in AWS Lambda quickly.
**Solution**:
.. code-block:: bash
# Navigate to Lambda testing directory
cd tests/lambda
# Build the test container (required first step)
make build
# Run basic compatibility tests
make test-lambda
# Run performance benchmarks
make test-performance
.. code-block:: python
# Basic Lambda function with HoneyHive
import json
import os
from honeyhive import HoneyHiveTracer
# Initialize outside handler for container reuse
tracer = HoneyHiveTracer.init(
api_key=os.getenv("HH_API_KEY", "test-key"), # Or set HH_API_KEY environment variable
project=os.getenv("HH_PROJECT", "test-project"), # Or set HH_PROJECT environment variable
source="development", # Or set HH_SOURCE environment variable
test_mode=True, # Or set HH_TEST_MODE=true
disable_http_tracing=True # Optimize for Lambda (or set HH_DISABLE_HTTP_TRACING=true)
)
def lambda_handler(event, context):
"""Lambda handler with HoneyHive tracing."""
with tracer.trace("lambda_execution") as span:
span.set_attribute("lambda.request_id", context.aws_request_id)
span.set_attribute("lambda.function_name", context.function_name)
# Your business logic here
result = {"message": "HoneyHive works in Lambda!"}
return {
"statusCode": 200,
"body": json.dumps(result)
}
Why Lambda Testing Matters
--------------------------
**AWS Lambda Constraints**:
- **Cold Start Delays**: First invocation initialization time (target: <500ms)
- **Memory Constraints**: Limited memory environments (128MB - 10GB)
- **Execution Timeouts**: Maximum 15-minute execution limits
- **Networking Restrictions**: Limited outbound connectivity
- **Container Reuse**: Warm start optimizations for performance
- **Concurrency Limits**: Parallel execution constraints
**Lambda Execution Flow with HoneyHive SDK**:
.. mermaid::
%%{init: {'theme':'base', 'themeVariables': {'primaryColor': '#4F81BD', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#000000', 'lineColor': '#333333', 'mainBkg': 'transparent', 'secondBkg': 'transparent', 'tertiaryColor': 'transparent', 'clusterBkg': 'transparent', 'clusterBorder': '#000000', 'edgeLabelBackground': 'transparent', 'background': 'transparent'}, 'flowchart': {'linkColor': '#333333', 'linkWidth': 2}}}%%
graph TD
subgraph "Cold Start (First Invocation)"
COLD_INIT[Lambda Container Init
~100-200ms]
COLD_RUNTIME[Runtime Startup
~50-100ms]
COLD_SDK[SDK Import & Init
~153ms + 155ms]
COLD_TRACER[Tracer Setup
Session Creation]
COLD_HANDLER[Handler Execution
Business Logic]
COLD_FLUSH[Force Flush
Ensure Delivery]
COLD_TOTAL[Total: ~281ms overhead
+ handler time]
end
subgraph "Warm Start (Subsequent Invocations)"
WARM_REUSE[Container Reuse
~1-5ms]
WARM_TRACER[Existing Tracer
No Initialization]
WARM_HANDLER[Handler Execution
Business Logic]
WARM_FLUSH[Force Flush
Quick Delivery]
WARM_TOTAL[Total: ~52ms overhead
+ handler time]
end
COLD_INIT --> COLD_RUNTIME
COLD_RUNTIME --> COLD_SDK
COLD_SDK --> COLD_TRACER
COLD_TRACER --> COLD_HANDLER
COLD_HANDLER --> COLD_FLUSH
COLD_FLUSH --> COLD_TOTAL
WARM_REUSE --> WARM_TRACER
WARM_TRACER --> WARM_HANDLER
WARM_HANDLER --> WARM_FLUSH
WARM_FLUSH --> WARM_TOTAL
COLD_TOTAL -.->|Container Reuse| WARM_REUSE
classDef cold fill:#1565c0,stroke:#000000,stroke-width:3px,color:#ffffff
classDef warm fill:#2e7d32,stroke:#000000,stroke-width:3px,color:#ffffff
classDef total fill:#ef6c00,stroke:#000000,stroke-width:3px,color:#ffffff
class COLD_INIT,COLD_RUNTIME,COLD_SDK,COLD_TRACER,COLD_HANDLER,COLD_FLUSH cold
class WARM_REUSE,WARM_TRACER,WARM_HANDLER,WARM_FLUSH warm
class COLD_TOTAL,WARM_TOTAL total
**HoneyHive SDK Optimizations**:
- ✅ **Sub-500ms Cold Starts**: Validated performance (actual: ~281ms)
- ✅ **<50MB Memory Overhead**: Efficient resource usage
- ✅ **Production Bundle Testing**: Native Linux dependencies
- ✅ **Graceful Degradation**: Works when HoneyHive API unavailable
- ✅ **Container Reuse**: Optimized for warm start scenarios
Lambda Testing Infrastructure
-----------------------------
**Production-Ready Bundle Container Approach**:
.. mermaid::
%%{init: {'theme':'base', 'themeVariables': {'primaryColor': '#4F81BD', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#000000', 'lineColor': '#333333', 'mainBkg': 'transparent', 'secondBkg': 'transparent', 'tertiaryColor': 'transparent', 'clusterBkg': 'transparent', 'clusterBorder': '#000000', 'edgeLabelBackground': 'transparent', 'background': 'transparent'}, 'flowchart': {'linkColor': '#333333', 'linkWidth': 2}}}%%
graph TD
subgraph "Development Testing"
LOCAL[Local Docker Testing]
BUNDLE[Bundle Container Build]
COMPAT[Compatibility Tests]
PERF[Performance Benchmarks]
end
subgraph "CI/CD Pipeline"
MATRIX[Matrix Testing
Python 3.11-3.13
Memory 256-1024MB]
REGRESSION[Regression Detection]
GATES[Quality Gates]
end
subgraph "Production Validation"
DEPLOY[Real AWS Lambda Deploy]
PROD[Integration Tests]
MONITOR[Monitoring]
end
LOCAL --> BUNDLE
BUNDLE --> COMPAT
COMPAT --> PERF
PERF --> MATRIX
MATRIX --> REGRESSION
REGRESSION --> GATES
GATES --> DEPLOY
DEPLOY --> PROD
PROD --> MONITOR
classDef devStage fill:#1b5e20,stroke:#333333,stroke-width:2px,color:#ffffff
classDef ciStage fill:#1a237e,stroke:#333333,stroke-width:2px,color:#ffffff
classDef prodStage fill:#4a148c,stroke:#333333,stroke-width:2px,color:#ffffff
class LOCAL,BUNDLE,COMPAT,PERF devStage
class MATRIX,REGRESSION,GATES ciStage
class DEPLOY,PROD,MONITOR prodStage
**Key Testing Infrastructure**:
.. code-block:: text
tests/lambda/
├── Dockerfile.bundle-builder # ✅ Multi-stage bundle build
├── lambda_functions/ # Lambda function examples
│ ├── working_sdk_test.py # ✅ Basic functionality test
│ ├── cold_start_test.py # ✅ Performance measurement
│ └── basic_tracing.py # ✅ Simple tracing example
├── test_lambda_compatibility.py # ✅ Test suite implementation
├── test_lambda_performance.py # Performance benchmarks
├── Makefile # ✅ Build and test automation
└── README.md # Complete documentation
Local Lambda Testing
--------------------
**Problem**: Test Lambda functions locally during development.
**Solution - Basic Lambda Function**:
.. code-block:: python
"""Basic Lambda function to test HoneyHive SDK compatibility."""
import json
import os
import sys
import time
from typing import Any, Dict
# Add the SDK to the path (simulates pip install in real Lambda)
sys.path.insert(0, "/var/task")
try:
from honeyhive.tracer import HoneyHiveTracer
from honeyhive.tracer.decorators import trace
SDK_AVAILABLE = True
except ImportError as e:
print(f"❌ SDK import failed: {e}")
SDK_AVAILABLE = False
# Initialize tracer outside handler for reuse across invocations
tracer = None
if SDK_AVAILABLE:
try:
tracer = HoneyHiveTracer.init(
api_key=os.getenv("HH_API_KEY", "test-key"), source="development"
session_name="lambda-basic-test",
test_mode=True, # Enable test mode for Lambda
disable_http_tracing=True, # Avoid Lambda networking issues
)
print("✅ HoneyHive tracer initialized successfully")
except Exception as e:
print(f"❌ Tracer initialization failed: {e}")
tracer = None
@trace(tracer=tracer, event_type="lambda", event_name="basic_operation")
def process_data(data: Dict[str, Any]) -> Dict[str, Any]:
"""Process data with tracing."""
if not tracer:
return {"error": "Tracer not available"}
# Simulate work
time.sleep(0.1)
# Test span enrichment
from honeyhive.tracer.otel_tracer import enrich_span
with enrich_span(
metadata={"lambda_test": True, "data_size": len(str(data))},
outputs={"processed": True},
error=None,
tracer=tracer
):
result = {
"processed_data": data,
"timestamp": time.time(),
"lambda_context": {
"function_name": os.getenv("AWS_LAMBDA_FUNCTION_NAME"),
"function_version": os.getenv("AWS_LAMBDA_FUNCTION_VERSION"),
"memory_limit": os.getenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128"),
},
}
return result
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
"""Lambda handler function."""
print(f"🚀 Lambda invocation started: {getattr(context, 'aws_request_id', 'test')}")
start_time = time.time()
try:
# Test basic SDK functionality
if not SDK_AVAILABLE:
return {
"statusCode": 500,
"body": json.dumps({"error": "HoneyHive SDK not available"}),
}
if not tracer:
return {
"statusCode": 500,
"body": json.dumps({"error": "HoneyHive tracer not initialized"}),
}
# Create a span for the entire Lambda execution
with tracer.start_span("lambda_execution") as span:
span.set_attribute("lambda.request_id", getattr(context, "aws_request_id", "test"))
span.set_attribute("lambda.function_name", os.getenv("AWS_LAMBDA_FUNCTION_NAME", "unknown"))
span.set_attribute("lambda.remaining_time", getattr(context, "get_remaining_time_in_millis", lambda: 30000)())
# Process the event
result = process_data(event)
# Test force_flush before Lambda completes
flush_success = tracer.force_flush(timeout_millis=2000)
span.set_attribute("lambda.flush_success", flush_success)
execution_time = (time.time() - start_time) * 1000
return {
"statusCode": 200,
"body": json.dumps({
"message": "HoneyHive SDK works in Lambda!",
"execution_time_ms": execution_time,
"flush_success": flush_success,
"result": result,
}),
}
except Exception as e:
print(f"❌ Lambda execution failed: {e}")
return {
"statusCode": 500,
"body": json.dumps({
"error": str(e),
"execution_time_ms": (time.time() - start_time) * 1000,
}),
}
finally:
# Ensure cleanup
if tracer:
try:
tracer.force_flush(timeout_millis=1000)
except Exception as e:
print(f"⚠️ Final flush failed: {e}")
**Solution - Cold Start Performance Testing**:
.. code-block:: python
"""Test HoneyHive SDK behavior during Lambda cold starts."""
import json
import os
import sys
import time
from typing import Any, Dict
sys.path.insert(0, "/var/task")
# Track cold start behavior
COLD_START = True
INITIALIZATION_TIME = time.time()
try:
from honeyhive.tracer import HoneyHiveTracer
SDK_IMPORT_TIME = time.time() - INITIALIZATION_TIME
print(f"✅ SDK import took: {SDK_IMPORT_TIME * 1000:.2f}ms")
except ImportError as e:
print(f"❌ SDK import failed: {e}")
SDK_IMPORT_TIME = -1
# Initialize tracer and measure time
tracer = None
TRACER_INIT_TIME = -1
if "honeyhive" in sys.modules:
init_start = time.time()
try:
tracer = HoneyHiveTracer.init(
api_key=os.getenv("HH_API_KEY", "test-key"), source="development"
session_name="cold-start-test",
test_mode=True,
disable_http_tracing=True
)
TRACER_INIT_TIME = time.time() - init_start
print(f"✅ Tracer initialization took: {TRACER_INIT_TIME * 1000:.2f}ms")
except Exception as e:
print(f"❌ Tracer initialization failed: {e}")
TRACER_INIT_TIME = -1
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
"""Test cold start performance impact."""
global COLD_START
handler_start = time.time()
current_cold_start = COLD_START
COLD_START = False # Subsequent invocations are warm starts
print(f"🔥 {'Cold' if current_cold_start else 'Warm'} start detected")
try:
if not tracer:
return {
"statusCode": 500,
"body": json.dumps({
"error": "Tracer not available",
"cold_start": current_cold_start,
"sdk_import_time_ms": SDK_IMPORT_TIME * 1000 if SDK_IMPORT_TIME > 0 else -1,
"tracer_init_time_ms": TRACER_INIT_TIME * 1000 if TRACER_INIT_TIME > 0 else -1,
}),
}
# Test SDK operations during cold/warm start
with tracer.start_span("cold_start_test") as span:
span.set_attribute("lambda.cold_start", current_cold_start)
span.set_attribute("lambda.sdk_import_time_ms", SDK_IMPORT_TIME * 1000 if SDK_IMPORT_TIME > 0 else -1)
span.set_attribute("lambda.tracer_init_time_ms", TRACER_INIT_TIME * 1000 if TRACER_INIT_TIME > 0 else -1)
# Simulate some work
work_start = time.time()
from honeyhive.tracer.otel_tracer import enrich_span
with enrich_span(
tracer=tracer,
metadata={"test_type": "cold_start", "iteration": event.get("iteration", 1)},
outputs={"cold_start": current_cold_start},
error=None
):
# Simulate processing
time.sleep(0.05)
work_time = time.time() - work_start
span.set_attribute("lambda.work_time_ms", work_time * 1000)
# Test flush performance
flush_start = time.time()
flush_success = tracer.force_flush(timeout_millis=1000)
flush_time = time.time() - flush_start
total_handler_time = time.time() - handler_start
return {
"statusCode": 200,
"body": json.dumps({
"message": "Cold start test completed",
"cold_start": current_cold_start,
"timings": {
"sdk_import_ms": SDK_IMPORT_TIME * 1000 if SDK_IMPORT_TIME > 0 else -1,
"tracer_init_ms": TRACER_INIT_TIME * 1000 if TRACER_INIT_TIME > 0 else -1,
"handler_total_ms": total_handler_time * 1000,
"work_time_ms": work_time * 1000,
"flush_time_ms": flush_time * 1000,
},
"flush_success": flush_success,
"performance_impact": {
"init_overhead_ms": (SDK_IMPORT_TIME + TRACER_INIT_TIME) * 1000 if current_cold_start else 0,
"runtime_overhead_ms": (work_time + flush_time) * 1000,
},
}),
}
except Exception as e:
return {
"statusCode": 500,
"body": json.dumps({
"error": str(e),
"cold_start": current_cold_start,
"handler_time_ms": (time.time() - handler_start) * 1000,
}),
}
**Building and Running Local Tests**:
.. code-block:: bash
# Navigate to Lambda test directory
cd tests/lambda
# Build the bundle container
make build
# Run basic functionality test
make test-lambda
# Run cold start performance test
make test-cold-start
# Manual container testing
docker run --rm -p 9000:8080 \
-e HH_API_KEY=test-key \
-e HH_PROJECT=test-project \
honeyhive-lambda:bundle-native
# Test with curl
curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" \
-H "Content-Type: application/json" \
-d '{"test": "manual", "iteration": 1}'
Performance Testing & Benchmarking
----------------------------------
**Problem**: Validate Lambda performance meets requirements.
**Solution - Automated Performance Testing**:
.. code-block:: python
"""Performance tests for HoneyHive SDK in AWS Lambda environment."""
import json
import statistics
import time
from typing import Any, Dict, List
import docker
import pytest
import requests
class TestLambdaPerformance:
"""Performance tests for Lambda environment."""
@pytest.fixture(scope="class")
def performance_container(self):
"""Start optimized Lambda container for performance testing."""
client = docker.from_env()
container = client.containers.run(
"honeyhive-lambda:bundle-native",
command="cold_start_test.lambda_handler",
ports={"8080/tcp": 9100},
environment={
"AWS_LAMBDA_FUNCTION_NAME": "honeyhive-performance-test",
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "256",
"HH_API_KEY": "test-key",
"HH_PROJECT": "lambda-performance-test",
"HH_SOURCE": "performance-test",
"HH_TEST_MODE": "true",
},
detach=True,
remove=True
)
# Wait for container to be ready
time.sleep(5)
yield container
try:
container.stop()
except:
pass
def invoke_lambda_timed(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Invoke Lambda and measure timing."""
url = "http://localhost:9100/2015-03-31/functions/function/invocations"
start_time = time.time()
response = requests.post(
url, json=payload, headers={"Content-Type": "application/json"}, timeout=30
)
total_time = (time.time() - start_time) * 1000
result = response.json()
result["_test_total_time_ms"] = total_time
return result
@pytest.mark.benchmark
def test_cold_start_performance(self, performance_container):
"""Benchmark cold start performance."""
result = self.invoke_lambda_timed({"test": "cold_start_benchmark"})
assert result["statusCode"] == 200
body = json.loads(result["body"])
timings = body.get("timings", {})
# Collect metrics
metrics = {
"cold_start": body.get("cold_start", True),
"total_time_ms": result["_test_total_time_ms"],
"sdk_import_ms": timings.get("sdk_import_ms", 0),
"tracer_init_ms": timings.get("tracer_init_ms", 0),
"handler_total_ms": timings.get("handler_total_ms", 0),
"work_time_ms": timings.get("work_time_ms", 0),
"flush_time_ms": timings.get("flush_time_ms", 0),
}
# Performance assertions
assert metrics["sdk_import_ms"] < 200, f"SDK import too slow: {metrics['sdk_import_ms']}ms"
assert metrics["tracer_init_ms"] < 300, f"Tracer init too slow: {metrics['tracer_init_ms']}ms"
assert metrics["total_time_ms"] < 2000, f"Total time too slow: {metrics['total_time_ms']}ms"
return metrics
@pytest.mark.benchmark
def test_warm_start_performance(self, performance_container):
"""Benchmark warm start performance."""
# First invoke to warm up
self.invoke_lambda_timed({"test": "warmup"})
# Then measure warm start performance
warm_times = []
for i in range(5):
result = self.invoke_lambda_timed({"test": f"warm_start_{i}"})
assert result["statusCode"] == 200
body = json.loads(result["body"])
# Should be warm start
assert body.get("cold_start") is False
warm_times.append(body.get("timings", {}).get("handler_total_ms", 0))
avg_warm_time = statistics.mean(warm_times)
# Warm starts should be fast
assert avg_warm_time < 100, f"Warm start too slow: {avg_warm_time:.2f}ms"
return {"average_warm_start_ms": avg_warm_time, "times": warm_times}
@pytest.mark.benchmark
def test_memory_efficiency(self, performance_container):
"""Test memory usage efficiency."""
result = self.invoke_lambda_timed({"test": "memory_test"})
assert result["statusCode"] == 200
# In real scenarios, would check container memory usage
# For now, verify operation completes without memory errors
body = json.loads(result["body"])
assert "error" not in body or body["error"] is None
**Performance Benchmarks & Results**:
.. mermaid::
%%{init: {'theme':'base', 'themeVariables': {'primaryColor': '#4F81BD', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#000000', 'lineColor': '#333333', 'mainBkg': 'transparent', 'secondBkg': 'transparent', 'tertiaryColor': 'transparent', 'clusterBkg': 'transparent', 'clusterBorder': '#000000', 'edgeLabelBackground': 'transparent', 'background': 'transparent'}, 'flowchart': {'linkColor': '#333333', 'linkWidth': 2}}}%%
graph LR
subgraph "Test Configurations"
M256[256MB Memory]
M512[512MB Memory]
M1024[1024MB Memory]
end
subgraph "Performance Tests"
COLD[Cold Start Tests
Target: <500ms
Measured: 281ms]
WARM[Warm Start Tests
Target: <100ms
Measured: 52ms]
MEM[Memory Usage Tests
Target: <50MB
Measured: <50MB]
LOAD[Load Tests
Target: >95%
Measured: >95%]
end
subgraph "Python Versions"
P311[Python 3.11]
P312[Python 3.12]
P313[Python 3.13]
end
subgraph "Test Results"
PASS[✅ All Tests Pass
281ms cold start
52ms warm start
<50MB overhead]
TREND[📈 Performance Trending
Historical Analysis
Regression Detection]
end
M256 --> COLD
M512 --> WARM
M1024 --> MEM
P311 --> LOAD
P312 --> LOAD
P313 --> LOAD
COLD --> PASS
WARM --> PASS
MEM --> PASS
LOAD --> PASS
PASS --> TREND
classDef config fill:#1565c0,stroke:#000000,stroke-width:3px,color:#ffffff
classDef test fill:#7b1fa2,stroke:#000000,stroke-width:3px,color:#ffffff
classDef version fill:#2e7d32,stroke:#000000,stroke-width:3px,color:#ffffff
classDef result fill:#ef6c00,stroke:#000000,stroke-width:3px,color:#ffffff
class M256,M512,M1024 config
class COLD,WARM,MEM,LOAD test
class P311,P312,P313 version
class PASS,TREND result
.. list-table:: Validated Lambda Performance Results
:header-rows: 1
:widths: 25 25 25 25
* - Metric
- Target
- Actual (Bundle)
- Status
* - SDK Import Time
- < 200ms
- ~153ms
- ✅ PASS
* - Tracer Initialization
- < 300ms
- ~155ms
- ✅ PASS
* - Cold Start Total
- < 500ms
- ~281ms
- ✅ PASS
* - Warm Start Average
- < 100ms
- ~52ms
- ✅ PASS
* - Memory Overhead
- < 50MB
- <50MB
- ✅ PASS
**Memory Configuration Performance**:
.. list-table:: Performance by Memory Configuration
:header-rows: 1
:widths: 25 25 25 25
* - Memory (MB)
- Cold Start (ms)
- Warm Start (ms)
- SDK Overhead (ms)
* - 256
- 650-900
- 3-10
- 35-50
* - 512
- 450-700
- 2-8
- 25-40
* - 1024
- 350-550
- 1-5
- 15-30
CI/CD Integration Testing
-------------------------
**Problem**: Automate Lambda testing in CI/CD pipelines.
**CI/CD Lambda Testing Flow**:
.. mermaid::
%%{init: {'theme':'base', 'themeVariables': {'primaryColor': '#4F81BD', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#000000', 'lineColor': '#333333', 'mainBkg': 'transparent', 'secondBkg': 'transparent', 'tertiaryColor': 'transparent', 'clusterBkg': 'transparent', 'clusterBorder': '#000000', 'edgeLabelBackground': 'transparent', 'background': 'transparent'}, 'flowchart': {'linkColor': '#333333', 'linkWidth': 2}}}%%
graph TD
PR[Pull Request Created]
subgraph "Automated Testing Matrix"
PY311[Python 3.11 Tests]
PY312[Python 3.12 Tests]
PY313[Python 3.13 Tests]
M256[256MB Memory Tests]
M512[512MB Memory Tests]
M1024[1024MB Memory Tests]
end
subgraph "Quality Gates"
PERF[Performance Gate
Cold Start < 1000ms
Memory < 100MB
Success > 90%]
COMPAT[Compatibility Gate
All Python Versions
All Memory Configs]
REGRESS[Regression Gate
±20% Performance
Historical Comparison]
end
subgraph "Results"
PASS[✅ All Gates Pass
Merge Approved]
FAIL[❌ Gates Failed
Block Merge
Notify Developer]
WARN[⚠️ Performance Warning
Manual Review Required]
end
PR --> PY311
PR --> PY312
PR --> PY313
PY311 --> M256
PY312 --> M512
PY313 --> M1024
M256 --> PERF
M512 --> COMPAT
M1024 --> REGRESS
PERF --> PASS
PERF --> FAIL
PERF --> WARN
COMPAT --> PASS
COMPAT --> FAIL
REGRESS --> WARN
REGRESS --> PASS
classDef trigger fill:#1565c0,stroke:#000000,stroke-width:3px,color:#ffffff
classDef test fill:#7b1fa2,stroke:#000000,stroke-width:3px,color:#ffffff
classDef gate fill:#ef6c00,stroke:#000000,stroke-width:3px,color:#ffffff
classDef success fill:#2e7d32,stroke:#000000,stroke-width:3px,color:#ffffff
classDef warning fill:#f9a825,stroke:#000000,stroke-width:3px,color:#ffffff
classDef failure fill:#c62828,stroke:#000000,stroke-width:3px,color:#ffffff
class PR trigger
class PY311,PY312,PY313,M256,M512,M1024 test
class PERF,COMPAT,REGRESS gate
class PASS success
class WARN warning
class FAIL failure
**Solution - GitHub Actions Workflow**:
.. code-block:: yaml
# .github/workflows/lambda-tests.yml
name: Lambda Testing Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 6 * * *' # Daily performance regression testing
jobs:
lambda-compatibility:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.11, 3.12, 3.13]
memory-size: [256, 512, 1024]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox docker
- name: Build Lambda test containers
run: |
cd tests/lambda
make build
- name: Run Lambda compatibility tests
env:
HH_API_KEY: ${{ secrets.HH_TEST_API_KEY }}
HH_PROJECT: "ci-lambda-test"
HH_SOURCE: "github-actions"
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: ${{ matrix.memory-size }}
run: |
cd tests/lambda
make test-lambda
- name: Run Lambda performance tests
env:
HH_API_KEY: ${{ secrets.HH_TEST_API_KEY }}
run: |
cd tests/lambda
make test-performance
- name: Upload performance results
uses: actions/upload-artifact@v3
if: always()
with:
name: lambda-performance-${{ matrix.python-version }}-${{ matrix.memory-size }}mb
path: tests/lambda/performance-results.json
**CI/CD Performance Gates**:
.. list-table:: Automated Quality Gates
:header-rows: 1
:widths: 30 20 20 30
* - Metric
- Target
- Threshold
- Action on Failure
* - Cold Start Time
- < 500ms
- < 1000ms
- Block merge if > 1000ms
* - Warm Start Time
- < 100ms
- < 200ms
- Warning if > 100ms
* - Memory Usage
- < 50MB overhead
- < 100MB
- Block merge if > 100MB
* - Success Rate
- > 95%
- > 90%
- Block merge if < 90%
Production Lambda Testing
-------------------------
**Problem**: Test with real AWS Lambda deployments.
**Production Lambda Testing Architecture**:
.. mermaid::
%%{init: {'theme':'base', 'themeVariables': {'primaryColor': '#4F81BD', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#000000', 'lineColor': '#333333', 'mainBkg': 'transparent', 'secondBkg': 'transparent', 'tertiaryColor': 'transparent', 'clusterBkg': 'transparent', 'clusterBorder': '#000000', 'edgeLabelBackground': 'transparent', 'background': 'transparent'}, 'flowchart': {'linkColor': '#333333', 'linkWidth': 2}}}%%
graph TB
subgraph "AWS Lambda Environment"
LAMBDA[AWS Lambda Function
honeyhive-sdk-test]
RUNTIME[Lambda Runtime
Python 3.11/3.12/3.13]
MEM[Memory Configurations
256MB/512MB/1024MB]
end
subgraph "HoneyHive SDK"
SDK[HoneyHive SDK Bundle]
TRACER[Multi-Instance Tracers]
INSTR[OpenAI Instrumentors]
end
subgraph "Real Integration Tests"
COLD[Cold Start Validation
10 iterations]
WARM[Warm Start Validation
50 iterations]
LOAD[Load Testing
Concurrent invocations]
ERROR[Error Handling
Network failures]
end
subgraph "HoneyHive Platform"
API[HoneyHive API]
DASH[Dashboard Validation]
TRACES[Trace Data Verification]
METRICS[Performance Metrics]
end
subgraph "Monitoring & Alerting"
WATCH[CloudWatch Logs]
ALERT[Performance Alerts]
SLACK[Slack Notifications]
FEEDBACK[Developer Feedback Loop]
end
LAMBDA --> SDK
RUNTIME --> SDK
MEM --> SDK
SDK --> TRACER
SDK --> INSTR
TRACER --> COLD
TRACER --> WARM
TRACER --> LOAD
TRACER --> ERROR
COLD --> API
WARM --> API
LOAD --> API
ERROR --> API
API --> DASH
API --> TRACES
API --> METRICS
METRICS --> WATCH
TRACES --> ALERT
DASH --> SLACK
ALERT --> FEEDBACK
classDef aws fill:#ff9900,stroke:#232f3e,stroke-width:2px,color:#ffffff
classDef honeyhive fill:#4f81bd,stroke:#2c5aa0,stroke-width:2px,color:#ffffff
classDef test fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
classDef platform fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
classDef monitor fill:#f57c00,stroke:#e65100,stroke-width:2px,color:#ffffff
class LAMBDA,RUNTIME,MEM aws
class SDK,TRACER,INSTR honeyhive
class COLD,WARM,LOAD,ERROR test
class API,DASH,TRACES,METRICS platform
class WATCH,ALERT,SLACK,FEEDBACK monitor
**Solution - Real AWS Lambda Testing**:
.. code-block:: python
"""Production Lambda test with real API integration."""
import json
import os
import openai
from honeyhive import HoneyHiveTracer
from openinference.instrumentation.openai import OpenAIInstrumentor
def lambda_handler(event, context):
"""Production Lambda test with real API calls."""
# Initialize with production settings
# Step 1: Initialize HoneyHive tracer first (without instrumentors)
tracer = HoneyHiveTracer.init(
api_key=os.environ.get("HH_API_KEY"), # Or set HH_API_KEY environment variable
project=os.environ.get("HH_PROJECT"), # Or set HH_PROJECT environment variable
source="development" # Or set HH_SOURCE environment variable
)
# Step 2: Initialize instrumentor separately with tracer_provider
openai_instrumentor = OpenAIInstrumentor()
openai_instrumentor.instrument(tracer_provider=tracer.provider)
try:
with tracer.start_span("lambda-openai-test") as span:
span.set_attribute("lambda.function_name", context.function_name)
span.set_attribute("lambda.request_id", context.aws_request_id)
# Make real OpenAI API call (traced automatically)
client = openai.OpenAI()
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Test from Lambda"}],
max_tokens=50
)
return {
'statusCode': 200,
'body': json.dumps({
'message': 'Lambda integration test successful',
'response': response.choices[0].message.content,
'request_id': context.aws_request_id
})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({
'error': str(e),
'request_id': context.aws_request_id
})
}
**Deployment Testing Script**:
.. code-block:: bash
#!/bin/bash
# Deploy and test real Lambda function
# Build deployment package
cd tests/lambda
./build-deployment-package.sh
# Deploy to AWS Lambda
aws lambda update-function-code \
--function-name honeyhive-sdk-test \
--zip-file fileb://deployment-package.zip
# Run integration tests
python test_real_lambda_deployment.py \
--function-name honeyhive-sdk-test \
--iterations 10 \
--test-cold-start \
--test-warm-start
Lambda Optimization Best Practices
----------------------------------
**Problem**: Optimize HoneyHive SDK for Lambda performance.
**Solution - Configuration Optimization**:
.. code-block:: python
# Optimized Lambda configuration
# Step 1: Initialize HoneyHive tracer first (without instrumentors)
tracer = HoneyHiveTracer.init(
api_key=os.environ.get("HH_API_KEY"), # Or set HH_API_KEY environment variable
project=os.environ.get("HH_PROJECT", "lambda-app"), # Or set HH_PROJECT environment variable
source="development", # Or set HH_SOURCE environment variable
session_name=os.environ.get("AWS_LAMBDA_FUNCTION_NAME", "lambda-function"),
# Optimize for Lambda constraints
test_mode=os.environ.get("HH_TEST_MODE", "false").lower() == "true", # Or set HH_TEST_MODE environment variable
disable_http_tracing=True, # Reduce overhead in Lambda (or set HH_DISABLE_HTTP_TRACING=true)
)
# Step 2: Initialize instrumentor separately with tracer_provider
openai_instrumentor = OpenAIInstrumentor() # Only needed instrumentors
openai_instrumentor.instrument(tracer_provider=tracer.provider)
**Performance Optimization Checklist**:
1. **Minimize Cold Start Impact**:
- Initialize tracer outside handler when possible
- Use connection pooling for HTTP requests
- Optimize import statements and dependencies
- Leverage Lambda container reuse
2. **Memory Management**:
- Monitor memory usage patterns with CloudWatch
- Clean up resources properly in finally blocks
- Use appropriate memory allocation (256MB+ recommended)
- Test with different memory configurations
3. **Error Handling**:
- Implement comprehensive error catching
- Log errors with structured logging for CloudWatch
- Graceful degradation strategies when HoneyHive is unavailable
- Test timeout scenarios
4. **Performance Optimization**:
- Use ``disable_http_tracing=True`` to reduce overhead
- Enable ``test_mode=True`` for non-production environments
- Use ``force_flush()`` with appropriate timeouts
- Initialize instrumentors selectively
**Lambda-Specific Environment Variables**:
.. code-block:: bash
# Lambda environment variables
HH_API_KEY=your_api_key
HH_PROJECT=lambda-project
HH_SOURCE=aws-lambda
HH_TEST_MODE=false
HH_DISABLE_HTTP_TRACING=true
# AWS Lambda context
AWS_LAMBDA_FUNCTION_NAME=your-function-name
AWS_LAMBDA_FUNCTION_VERSION=$LATEST
AWS_LAMBDA_FUNCTION_MEMORY_SIZE=512
Troubleshooting Lambda Issues
-----------------------------
**Problem**: Debug common Lambda testing issues.
**Common Issues & Solutions**:
**Issue**: Cold start times too high
.. code-block:: python
# Solution: Optimize imports and initialization
import sys
import time
# Track import times
start_time = time.time()
from honeyhive import HoneyHiveTracer
import_time = time.time() - start_time
print(f"Import time: {import_time * 1000:.2f}ms")
# Initialize outside handler
tracer = HoneyHiveTracer.init(
api_key="test-key",
test_mode=True,
disable_http_tracing=True # Reduces startup overhead
)
**Issue**: Memory usage too high
.. code-block:: python
# Solution: Monitor and optimize memory
import psutil
import os
def lambda_handler(event, context):
process = psutil.Process(os.getpid())
initial_memory = process.memory_info().rss
# Your HoneyHive tracing code here
final_memory = process.memory_info().rss
memory_increase = final_memory - initial_memory
print(f"Memory increase: {memory_increase / 1024 / 1024:.2f}MB")
**Issue**: Network timeouts
.. code-block:: python
# Solution: Configure appropriate timeouts
tracer = HoneyHiveTracer.init(
api_key="test-key",
test_mode=True,
# Configure connection timeout
timeout=5.0, # 5 second timeout
# Use force_flush with timeout
)
# Always use timeout in flush
def lambda_handler(event, context):
with tracer.trace("lambda-operation") as span:
# Your logic here
pass
# Flush with timeout before Lambda ends
tracer.force_flush(timeout_millis=2000)
**Issue**: Container reuse problems
.. code-block:: python
# Solution: Design for container reuse
import threading
# Global state that survives container reuse
_tracer_lock = threading.Lock()
_tracer_instance = None
def get_tracer():
global _tracer_instance
if _tracer_instance is None:
with _tracer_lock:
if _tracer_instance is None:
_tracer_instance = HoneyHiveTracer.init(
api_key=os.environ.get("HH_API_KEY"),
test_mode=True
)
return _tracer_instance
Lambda Testing Commands
-----------------------
**Local Testing Commands**:
.. code-block:: bash
# Navigate to Lambda testing
cd tests/lambda
# Build containers
make build
# Run all Lambda tests
make test
# Run specific test types
make test-lambda # Basic compatibility
make test-cold-start # Cold start performance
make test-performance # Full performance suite
# Debug Lambda container
make debug-shell
# Clean up
make clean
**Testing with Different Configurations**:
.. code-block:: bash
# Test with different memory sizes
MEMORY_SIZE=256 make test-performance
MEMORY_SIZE=512 make test-performance
MEMORY_SIZE=1024 make test-performance
# Test with different Python versions
PYTHON_VERSION=3.11 make build
PYTHON_VERSION=3.12 make build
PYTHON_VERSION=3.13 make build
# Test with real API
HH_API_KEY=your_key HH_TEST_MODE=false make test-lambda
**Pytest Commands**:
.. code-block:: bash
# Run Lambda test suite
pytest tests/lambda/ -v
# Run performance tests only
pytest tests/lambda/ -m "benchmark" -v
# Run with real AWS Lambda
pytest tests/lambda/ -m "real_aws" -v
# Run specific test file
pytest tests/lambda/test_lambda_performance.py -v
Advanced Lambda Testing Scenarios
---------------------------------
**Multi-Region Testing**:
.. code-block:: python
# Test across multiple AWS regions
regions = ["us-east-1", "us-west-2", "eu-west-1"]
for region in regions:
os.environ["AWS_DEFAULT_REGION"] = region
test_lambda_deployment(region)
**Concurrent Invocation Testing**:
.. code-block:: python
# Test concurrent Lambda invocations
import concurrent.futures
def test_concurrent_lambda_invocations():
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
futures = [
executor.submit(invoke_lambda_function, {"test": f"concurrent_{i}"})
for i in range(50)
]
results = [future.result() for future in futures]
assert all(r["statusCode"] == 200 for r in results)
**Error Injection Testing**:
.. code-block:: python
# Test Lambda behavior under various failure conditions
@pytest.mark.parametrize("error_type", [
"network_timeout",
"api_unavailable",
"memory_pressure",
"disk_full"
])
def test_lambda_error_resilience(error_type):
with inject_failure(error_type):
result = invoke_lambda_function({"test": error_type})
# Should handle gracefully, not crash
assert result["statusCode"] in [200, 500] # Controlled failure
See Also
--------
- :doc:`performance-testing` - Performance testing strategies
- :doc:`ci-cd-integration` - CI/CD integration patterns
- :doc:`../../tutorials/advanced-configuration` - Advanced Lambda configuration
- :doc:`../../how-to/deployment/production` - Production deployment guide
- :doc:`../../reference/configuration/environment-vars` - Environment configuration