Serverless
Purpose
Design, deploy, and operate serverless functions (AWS Lambda, Azure Functions, GCP Cloud Functions) with event-driven patterns, cold start optimization, monitoring, security, and cost management.
Agent Protocol
Trigger
Exact user phrases: "serverless", "lambda", "azure functions", "cloud functions", "functions", "faas", "step functions", "serverless framework", "cold start", "provisioned concurrency", "reserved concurrency".
Input Context
Cloud provider (AWS, Azure, GCP).
Runtime (Node.js, Python, Go, Java, .NET, Rust).
Event sources (API Gateway, SQS, S3, EventBridge, Kafka, Timer).
Deployment framework (Serverless Framework, SAM, CDK, Pulumi, Terraform).
Existing observability and security tools.
Output Artifact
Serverless function configuration with event source mapping, IAM, monitoring, and deployment config.
Response Format
YAML/JSON configuration (serverless.yml, SAM template) or Terraform HCL. No preamble.
Completion Criteria
Function code with handler, event source, IAM permissions.
Cold start strategy (provisioned concurrency, SnapStart, warmers).
Monitoring: error rate, latency, invocation count, throttles.
Cost estimate for expected invocation volume.
Security: least-privilege IAM, VPC if needed, secrets via env/SSM.
Deployment pipeline (CI/CD with testing and staged deployments).
Observability: CloudWatch or equivalent, structured logging, distributed tracing.
Max Response Length
400 lines.
Quick Start
Define handler function → Configure event source (API Gateway HTTP API) → Set IAM role (least privilege) → Set memory/timeout → Deploy with Serverless Framework → Monitor with CloudWatch → Tune provisioned concurrency for critical functions.
Decision Tree: Serverless Provider
Provider
Runtime Support
Event Sources
Cold Start
Cost Model
AWS Lambda
Node, Python, Go, Java, .NET, Ruby, Rust (custom)
15+ native triggers
1-10ms (SnapStart)
Per ms + requests
Azure Functions
C#, Node, Python, Java, PowerShell, Go (custom)
10+ native triggers
1-50ms (premium plan)
Per second + requests
GCP Cloud Functions
Node, Python, Go, Java, .NET, Ruby
8+ native triggers
100-500ms (1st gen)
Per second + invocations
Cloudflare Workers
JS/TS, WASM, Python (via Pyodide)
HTTP, KV, D1, R2, Queues
<1ms (v8 isolates)
Per request, very cheap
Knative / OpenFaaS
Any (container)
Any
0-1000ms
Container-based
Core Workflow
Step 1: Function Configuration
# serverless.yml (AWS Lambda)
service: user-service
frameworkVersion: '3'
provider:
name: aws
runtime: python3.12
region: us-east-1
stage: ${opt:stage, 'dev'}
memorySize: 512
timeout: 30
logRetentionInDays: 14
tracing:
lambda: true
apiGateway: true
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:Query
Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/users-${sls:stage}
- Effect: Allow
Action:
- ssm:GetParameter
Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/service/${sls:stage}/*
functions:
createUser:
handler: handlers/users.create
events:
- httpApi:
method: POST
path: /users
description: Create a new user record
memorySize: 1024
reservedConcurrency: 10
getUser:
handler: handlers/users.get
events:
- httpApi:
method: GET
path: /users/{id}
description: Get user by ID
provisionedConcurrency: 5
Step 2: Handler Implementation
# handlers/users.py
import json
import os
import boto3
from aws_lambda_powertools import Logger, Tracer, Metrics
from aws_lambda_powertools.metrics import MetricUnit
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
logger = Logger(service="user-service")
tracer = Tracer(service="user-service")
metrics = Metrics(namespace="UserService", service="user-service")
app = APIGatewayRestResolver()
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table(os.environ["TABLE_NAME"])
@app.post("/users")
@tracer.capture_method
def create_user():
body = app.current_event.json_body
user_id = body["id"]
# Validate input
if not body.get("email"):
return {"error": "email required"}, 400
table.put_item(Item={
"pk": f"USER#{user_id}",
"email": body["email"],
"name": body.get("name", ""),
"created_at": app.current_event.time
})
metrics.add_metric(name="UserCreated", unit=MetricUnit.Count, value=1)
return {"id": user_id, "message": "User created"}, 201
@app.get("/users/<id>")
@tracer.capture_method
def get_user(id: str):
result = table.get_item(Key={"pk": f"USER#{id}"})
user = result.get("Item")
if not user:
return {"error": "not found"}, 404
return {"user": user}, 200
@metrics.log_metrics
def handler(event, context):
# Structured logging already via powertools
logger.info("Processing request", extra={
"path": event.get("path"),
"method": event.get("httpMethod")
})
return app.resolve(event, context)
Step 3: Event Source Mapping (SQS + S3 + EventBridge)
# serverless.yml — event-driven functions
functions:
processOrder:
handler: handlers/orders.process
events:
- sqs:
arn: !GetAtt OrdersQueue.Arn
batchSize: 10
maximumBatchingWindowInSeconds: 5
- eventBridge:
pattern:
source:
- "custom.order"
detail-type:
- "OrderCreated"
- schedule:
rate: rate(5 minutes)
enabled: true
- s3:
bucket: !Ref UploadBucket
event: s3:ObjectCreated:*
rules:
- prefix: inbound/
- suffix: .csv
Step 4: Infrastructure with Terraform
resource "aws_lambda_function" "api" {
function_name = "api-handler-${var.environment}"
role = aws_iam_role.lambda_exec.arn
handler = "main.handler"
runtime = "python3.12"
filename = "function.zip"
source_code_hash = filebase64sha256("function.zip")
timeout = 30
memory_size = 512
publish = true
environment {
variables = {
TABLE_NAME = aws_dynamodb_table.users.name
STAGE = var.environment
POWERTOOLS_SERVICE_NAME = "api-handler"
}
}
tracing_config {
mode = "Active"
}
reserved_concurrent_executions = 20
}
resource "aws_lambda_function_event_invoke_config" "api" {
function_name = aws_lambda_function.api.function_name
qualifier = aws_lambda_function.api.version
destination_config {
on_failure {
destination = aws_sqs_queue.dlq.arn
}
on_success {
destination = aws_sns_topic.success.arn
}
}
}
resource "aws_lambda_permission" "apigw" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.api.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.api.execution_arn}/*/*"
}
Step 5: Cold Start Optimization
Strategies by runtime:
Python: 1-50ms cold starts — use AWS Lambda Web Adapter for faster responses
Enable provisioned concurrency for latency-critical endpoints
Node: 5-100ms — compile on deploy, minimize dependencies
Use esbuild bundler: tree-shake, reduce package size
Java: 500-5000ms — use SnapStart (Lambda SnapStart for Java 11+)
Prefer GraalVM native image (AWS provided, ~50ms cold start)
Go: 1-5ms — compile to native binary, almost no cold start
Best cold start of any interpreted/compiled runtime
.NET: 300-3000ms — use .NET 8 (Native AOT) for cold starts under 100ms
Rust: 1-3ms — compile to native, minimal cold start overhead
Provisioned concurrency:
- $0.0000040827 per GB-second for provisioned (vs. $0.0000133334 for on-demand)
- Schedule scaling: EventBridge rule to auto-scale provisioned concurrency
- Use for: API endpoints, latency-sensitive functions, canary deployments
Warmers (anti-pattern):
- CloudWatch scheduled event pinging functions every 5 min
- Not reliable — Lambda scales instances independently
- Better to use provisioned concurrency or SnapStart
Step 6: Serverless Security
IAM least privilege:
- Never use LambdaFullAccess — scope per function
- Use condition keys: sourceVpce, sourceIp, resourceArn, aws:SourceAccount
- Prefer execution role per function over shared role
- Rotate function URLs and API keys regularly
Secrets management:
- AWS: SSM Parameter Store (SecureString) or Secrets Manager
- Azure: Key Vault references in App Settings
- GCP: Secret Manager
- Never hardcode secrets in function code or env vars
- Use SDK to fetch at initialization (outside handler)
VPC considerations:
- Lambda in VPC: needs VPC endpoints for S3, DynamoDB, etc.
- No public internet by default — use NAT Gateway or VPC endpoints
- Adds 5-10ms cold start latency (ENI creation)
- Best practice: keep Lambda outside VPC unless accessing RDS/ElastiCache
Function URLs:
- Direct HTTPS endpoint for Lambda without API Gateway
- Support IAM auth or AWS_IAM auth
- Simple, no additional cost, but no custom domains natively
Code signing:
- AWS Signer for Lambda — sign and verify function code
- Enforce signing policies: require code signing profile
- Prevents tampered code from being deployed
Step 7: Serverless Observability
Structured logging:
- JSON format with correlation ID (API Gateway request ID or Lambda context)
- Fields: level, timestamp, service, message, request_id, duration_ms, error
- Use Lambda Powertools (Python, TypeScript, Java, .NET)
Distributed tracing:
- AWS: X-Ray with segments, subsegments, and annotations
- Azure: Application Insights
- GCP: Cloud Trace
- OpenTelemetry: collector as Lambda layer + OTLP exporter
Metrics:
- Invocations: count, errors, throttles, duration, concurrent executions
- Async: age of oldest message, dead-letter queue depth
- Business metrics: custom metrics via embedded metric format (EMF)
- Alert thresholds:
- Error rate > 1% for > 5 min
- Duration P99 > timeout * 0.8
- Throttles > 0 for > 1 min
- Dead-letter queue depth > 10
Step 8: Cost Management
Cost factors:
- Requests: $0.20 per 1M requests (AWS)
- Duration: $0.0000166667 per GB-second
- Provisioned concurrency: additional charge per GB-second
- Data transfer: Lambda → internet/$0.09 per GB, Lambda → same-region services is free
Optimization strategies:
- Right-size memory: more memory = proportionally more CPU (and cost)
- 1024 MB is the sweet spot for most Python/Node workloads
- Minimize runtime by optimizing code, reducing dependencies
- Batch SQS messages: batchSize > 1 reduces invocations
- Use Lambda function URLs for simple HTTP APIs (no API Gateway cost)
- Set reserved concurrency to prevent runaway cost from traffic spikes
- Use ephemeral storage /tmp for scratch files (512 MB - 10 GB)
- Monitor with cost allocation tags (Environment, Service, Team)
Estimated cost per 10M invocations (Python, 512 MB, 500 ms):
- Requests: $2.00
- Duration: ~$69.44
- Total: ~$71.44/month
Step 9: Advanced Patterns
Step Functions workflows:
- Express Workflows: high-volume, <5 min, $1 per 1000 state transitions
- Standard Workflows: long-running, up to 1 year, $0.025 per 1000 transitions
- Patterns: fan-out, parallel, wait for callback, saga (compensating transactions)
Lambda + DynamoDB Streams:
- Capture change data capture (CDC) events
- Fan out to SQS, SNS, EventBridge
- Handle duplicate events (idempotency via dynamodb-toolbox or idempotency key)
Lambda + WebSockets:
- API Gateway WebSocket API → Lambda integration
- $connect, $disconnect, $default routes
- Maintain connection IDs in DynamoDB
Lambda + EFS:
- Mount EFS for shared filesystem across concurrent invocations
- Cold start: ~1-2 seconds additional (mount time)
- Use for ML model inference, large reference data
Lambda response streaming:
- Stream responses up to 20 MB
- Pay-as-you-go response streaming (no API Gateway buffering)
- Good for large JSON, CSV generation, AI streaming
Rules
Every function must have a dead-letter queue (DLQ) for async invocations.
Set reserved concurrency for every production function to prevent runaway costs.
Enable X-Ray (or equivalent tracing) on all functions.
Use structured JSON logging with a correlation ID for traceability.
Never store secrets in environment variables — use SSM/Secrets Manager.
Align function memory with timeout: more memory = faster = less cost per invocation.
Deploy with immutable versioning (publish = true)—never use $LATEST in production.
Use Lambda versions and aliases for canary deployments (5% new, 95% old).
Test cold start behavior with your runtime before production — measure and tune.
Use Powertools (or equivalent) for logging, tracing, and metrics standardization.
Production Considerations
Lambda function URLs need resource-based policy or IAM authentication — don't leave open.
SQS batch processing: handle partial failures with reportBatchItemFailures.
Lambda in VPC: create a VPC endpoint for SSM and CloudWatch Logs.
SnapStart: requires Java 11+ and idempotent initialization code.
Recursive loops: Lambda writing to S3 → S3 event → Lambda (infinite loop protection needed).
aws:SourceAccount condition on Lambda resource policies to prevent confused deputy.
Lambda + RDS: use RDS Proxy to avoid connection pool exhaustion.
Lambda ephemeral storage default 512 MB — can increase to 10 GB for data processing.
Function URL CORS: configure allowed origins, methods, and headers.
Set function_response_type=RequestResponse for synchronous invocations.
CloudFront + Lambda@Edge: 5 sec viewer-request/response, 30 sec origin-request/response.
Anti-Patterns
No reserved concurrency — one buggy function consumes all account concurrency.
Maximum memory allocation without testing — linear cost increase with minimal perf benefit.
Synchronous calls between functions — use event-driven (SQS, SNS, EventBridge).
Monolithic function — violates single responsibility, cold start suffers.
Long timeouts (5+ min) — Lambda is for short-lived compute; use ECS/Step Functions.
No error handling in async handlers — failures are silently retried then discarded.
VPC for every function — unnecessary latency for functions that don't need it.
Using Lambda for persistent connections (WebSocket) without proper cleanup.
No idempotency handling — duplicates cause data corruption.
Not testing Lambda@Edge cold start latency — adds latency to every request.
References
references/serverless-advanced.md — Serverless Advanced Topics
references/serverless-fundamentals.md — Serverless Fundamentals
references/aws-lambda.md — AWS Lambda Deep Dive
references/azure-functions.md — Azure Functions Configuration
references/gcp-cloud-functions.md — GCP Cloud Functions
references/serverless-framework.md — Serverless Framework Deployment
references/step-functions.md — AWS Step Functions Workflows
references/lambda-monitoring.md — Lambda Monitoring and Observability
references/lambda-security.md — Lambda Security Best Practices
Handoff
devops-aws for API Gateway, DynamoDB, SQS, EventBridge integration.
devops-observability for AWS X-Ray and CloudWatch configuration.
devops-cicd-pipeline for CI/CD pipelines with Lambda deployment.
devops-security for IAM and secrets management.
devops-monitoring for Lambda-specific monitoring dashboards.
Architecture Decision Trees
Lambda vs Fargate vs ECS
Decision
Lambda (FaaS)
Fargate (Serverless Container)
ECS (Container Orchestration)
Execution model
Event-driven, short-lived
Long-running container
Long-running container
Max duration
15 minutes
Unlimited
Unlimited
Cold start
Yes (<1s provisioned concurrency)
No (always warm)
No (always warm)
Scaling
Instant (per-event)
Auto-scaling (minutes)
Auto-scaling (minutes)
Cost model
Per-invocation + duration
Per-hour (vCPU + memory)
Per-hour (EC2 instances)
State
Stateless (externalize to SQS/DynamoDB)
Stateful possible
Stateful possible
Best for
Event-driven, bursty, variable
Steady API workloads
Batch, ML, GPU workloads
API Gateway REST vs HTTP vs WebSocket
Aspect
REST API
HTTP API
WebSocket API
Latency
~50ms
~10ms
~50ms
Features
WAF, usage plans, API keys
JWT, CORS, cheaper
Real-time, bidirectional
Cost
Most expensive
Cheapest (~70% less)
Connection + message
Integration
Lambda, HTTP, Step Functions
Lambda, HTTP, Service Discovery
Lambda, DynamoDB
Use case
Public APIs with throttling
Microservices APIs
Chat, real-time updates
Implementation Patterns
Terraform: Event-driven Lambda with SQS and DynamoDB
resource "aws_lambda_function" "order_processor" {
function_name = "order-processor-${var.environment}"
runtime = "nodejs22.x"
handler = "index.handler"
filename = "${path.module}/function.zip"
source_code_hash = filebase64sha256("${path.module}/function.zip")
memory_size = 512
timeout = 30
reserved_concurrent_executions = 50
environment {
variables = {
TABLE_NAME = aws_dynamodb_table.orders.name
DLQ_QUEUE_URL = aws_sqs_queue.dlq.url
}
}
tracing_config {
mode = "Active"
}
}
resource "aws_lambda_event_source_mapping" "sqs_trigger" {
event_source_arn = aws_sqs_queue.order_events.arn
function_name = aws_lambda_function.order_processor.arn
batch_size = 10
maximum_batching_window_in_seconds = 5
scaling_config {
maximum_concurrency = 10
}
}
resource "aws_dynamodb_table" "orders" {
name = "orders-${var.environment}"
billing_mode = "PAY_PER_REQUEST"
hash_key = "orderId"
attribute {
name = "orderId"
type = "S"
}
ttl {
attribute_name = "ttl"
enabled = true
}
point_in_time_recovery {
enabled = true
}
}
resource "aws_sqs_queue" "dlq" {
name = "order-processor-dlq-${var.environment}"
message_retention_seconds = 1209600 # 14 days
visibility_timeout_seconds = 30
}
Bash: Lambda Deployment Script
#!/usr/bin/env bash
deploy_lambda() {
local function_name=$1
local source_dir=$2
# Install production dependencies
cd "$source_dir"
npm ci --production --ignore-scripts
# Package with esbuild for minimal bundle
npx esbuild index.js --bundle --minify --platform=node \
--outfile=dist/index.js --external:aws-sdk
# Create deployment package
cd dist
zip -r9 "../${function_name}.zip" .
# Deploy to Lambda
aws lambda update-function-code \
--function-name "$function_name" \
--zip-file "fileb://../${function_name}.zip"
# Publish version
aws lambda publish-version \
--function-name "$function_name"
# Update alias to point to new version
aws lambda update-alias \
--function-name "$function_name" \
--name production \
--function-version "$(aws lambda list-versions-by-function \
--function-name "$function_name" --query 'Versions[-1].Version' --output text)"
}
Production Considerations (Serverless-specific)
Enable provisioned concurrency for latency-sensitive functions to eliminate cold starts
Configure Lambda Powertools (TypeScript/Python/Java) for structured logging and tracing
Set function timeouts realistically — 30s for APIs, 5m for batch processors, never max unless needed
Implement idempotency in all event-driven functions (store processed event IDs in DynamoDB)
Use Lambda Extensions for secrets caching, APM agents, and sidecar processes
Enable CloudWatch Lambda Insights for memory profiling and cold start analysis
Set reserved concurrency per critical function to prevent noise from other functions starving it
Observer Pattern for Event Handling
`
interface EventObserver {
onEvent(event: T): Promise;
}
class EventBus {
private observers: Set<EventObserver> = new Set();
subscribe(observer: EventObserver): void {
this.observers.add(observer);
}
unsubscribe(observer: EventObserver): void {
this.observers.delete(observer);
}
async emit(event: T): Promise {
const results = Array.from(this.observers).map(o => o.onEvent(event));
await Promise.allSettled(results);
}
}
`
Configuration-Driven Approach
config: defaults: timeout: 30s retryCount: 3 overrides: production: timeout: 60s retryCount: 5 development: timeout: 300s retryCount: 1
Production Considerations
Deployment Checklist
Monitoring and Alerting
Metric
Threshold
Severity
Action
Error rate
> 1% over 5min
Critical
Page on-call
p99 latency
> 2s over 5min
Warning
Investigate
Throughput drop
> 50% over 1min
Critical
Check upstream
Queue depth
> 1000 over 1min
Warning
Scale consumers
Disk usage
> 85%
Warning
Clean or expand
Memory usage
> 90% heap
Critical
Restart or scale
Anti-Patterns
Anti-Pattern
Symptom
Root Cause
Solution
Premature optimization
Complex code for no measured benefit
Guessing instead of profiling
Measure first, optimize based on data
Copy-paste reuse
Duplicate code across codebase
Lack of abstraction
Extract shared logic into libraries
Gold-plating
Features with no current requirement
Over-engineering
YAGNI — build what's needed now
Magical thinking
Assumptions without validation
Skipping error handling
Handle all failure modes explicitly
Performance Optimization
Caching Strategy
Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge).
Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency).
Resource Pooling
Database connections: Pool of reusable connections (HikariCP, pgBouncer)
HTTP connections: Keep-alive + connection pooling for external calls
Thread pool: Bounded thread pools for async task execution
Profiling Methodology
Establish baseline with production traffic profile
Profile CPU with sampling profiler (pprof, perf, async-profiler)
Profile memory with heap dumps and allocation tracking
Profile I/O with strace/perf trace for syscall analysis
Profile latency with distributed tracing (OpenTelemetry)
Identify bottleneck, formulate hypothesis, implement fix
Re-profile to verify improvement, repeat
Security Considerations
Threat Modeling (STRIDE)
Spoofing: Identity validation, authentication
Tampering: Integrity checks, digital signatures
Repudiation: Audit logs, non-repudiation
Information disclosure: Encryption, access control
Denial of service: Rate limiting, resource quotas
Elevation of privilege: Principle of least privilege
Supply Chain Security
Dependency scanning: Snyk, Dependabot, Trivy
SBOM generation: CycloneDX or SPDX format
Signed commits: GPG or SSH commit signing
Artifact verification: Checksum validation, signature verification
Secrets Management
Secrets never in code — always in secrets manager (Vault, AWS Secrets Manager)
Rotation policy: Rotate database credentials every 90 days
Access audit: Log every secrets access, alert on anomalies
Encryption at rest and in transit for all secrets
Principle of least privilege: each service gets only its own secrets
Rules
Default-deny security posture — allow only explicitly required access.
All inputs validated, all outputs encoded, all errors handled.
Defend in depth — multiple layers of security controls.
Fail securely — errors default to safe behavior.
Log security-relevant events for audit and investigation.
Keep dependencies updated — automate vulnerability scanning.
Design for observability from day one, not as an afterthought.
Document all architectural decisions with rationale.
Review code for security, performance, and correctness before merging.
1 --- 2 name: serverless 3 description: Use this skill when the user says 'serverless', 'lambda', 'aws lambda', 'functions', 'function as a service', 'faas', 'azure functions', 'google cloud functions', 'knative', 'openfaas', 'serverless framework', 'chalice', 'zappa', 'apigw', 'api gateway', 'event-driven', 'cold start', 'provisioned concurrency', 'reserved concurrency', 'lambda layers', 'step functions', 'durable functions', 'serverless observability', 'serverless monitoring', 'serverless security', 'serverless cost', 'serverless best practices', 'serverless framework deployment'. Covers: AWS Lambda, Azure Functions, Google Cloud Functions, serverless framework, event-driven patterns, cold start optimization, monitoring, security, and cost management. 4 license: MIT 5 --- 6 7 # Serverless 8 9 ## Purpose 10 Design, deploy, and operate serverless functions (AWS Lambda, Azure Functions, GCP Cloud Functions) with event-driven patterns, cold start optimization, monitoring, security, and cost management. 11 12 ## Agent Protocol 13 14 ### Trigger 15 Exact user phrases: "serverless", "lambda", "azure functions", "cloud functions", "functions", "faas", "step functions", "serverless framework", "cold start", "provisioned concurrency", "reserved concurrency". 16 17 ### Input Context 18 - Cloud provider (AWS, Azure, GCP). 19 - Runtime (Node.js, Python, Go, Java, .NET, Rust). 20 - Event sources (API Gateway, SQS, S3, EventBridge, Kafka, Timer). 21 - Deployment framework (Serverless Framework, SAM, CDK, Pulumi, Terraform). 22 - Existing observability and security tools. 23 24 ### Output Artifact 25 Serverless function configuration with event source mapping, IAM, monitoring, and deployment config. 26 27 ### Response Format 28 YAML/JSON configuration (serverless.yml, SAM template) or Terraform HCL. No preamble. 29 30 ### Completion Criteria 31 - [ ] Function code with handler, event source, IAM permissions. 32 - [ ] Cold start strategy (provisioned concurrency, SnapStart, warmers). 33 - [ ] Monitoring: error rate, latency, invocation count, throttles. 34 - [ ] Cost estimate for expected invocation volume. 35 - [ ] Security: least-privilege IAM, VPC if needed, secrets via env/SSM. 36 - [ ] Deployment pipeline (CI/CD with testing and staged deployments). 37 - [ ] Observability: CloudWatch or equivalent, structured logging, distributed tracing. 38 39 ### Max Response Length 40 400 lines. 41 42 ## Quick Start 43 Define handler function → Configure event source (API Gateway HTTP API) → Set IAM role (least privilege) → Set memory/timeout → Deploy with Serverless Framework → Monitor with CloudWatch → Tune provisioned concurrency for critical functions. 44 45 ## Decision Tree: Serverless Provider 46 | Provider | Runtime Support | Event Sources | Cold Start | Cost Model | 47 |----------|----------------|---------------|------------|------------| 48 | **AWS Lambda** | Node, Python, Go, Java, .NET, Ruby, Rust (custom) | 15+ native triggers | 1-10ms (SnapStart) | Per ms + requests | 49 | **Azure Functions** | C#, Node, Python, Java, PowerShell, Go (custom) | 10+ native triggers | 1-50ms (premium plan) | Per second + requests | 50 | **GCP Cloud Functions** | Node, Python, Go, Java, .NET, Ruby | 8+ native triggers | 100-500ms (1st gen) | Per second + invocations | 51 | **Cloudflare Workers** | JS/TS, WASM, Python (via Pyodide) | HTTP, KV, D1, R2, Queues | <1ms (v8 isolates) | Per request, very cheap | 52 | **Knative / OpenFaaS** | Any (container) | Any | 0-1000ms | Container-based | 53 54 ## Core Workflow 55 56 ### Step 1: Function Configuration 57 ```yaml 58 # serverless.yml (AWS Lambda) 59 service: user-service 60 frameworkVersion: '3' 61 62 provider: 63 name: aws 64 runtime: python3.12 65 region: us-east-1 66 stage: ${opt:stage, 'dev'} 67 memorySize: 512 68 timeout: 30 69 logRetentionInDays: 14 70 tracing: 71 lambda: true 72 apiGateway: true 73 iam: 74 role: 75 statements: 76 - Effect: Allow 77 Action: 78 - dynamodb:GetItem 79 - dynamodb:PutItem 80 - dynamodb:Query 81 Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/users-${sls:stage} 82 - Effect: Allow 83 Action: 84 - ssm:GetParameter 85 Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/service/${sls:stage}/* 86 87 functions: 88 createUser: 89 handler: handlers/users.create 90 events: 91 - httpApi: 92 method: POST 93 path: /users 94 description: Create a new user record 95 memorySize: 1024 96 reservedConcurrency: 10 97 98 getUser: 99 handler: handlers/users.get 100 events: 101 - httpApi: 102 method: GET 103 path: /users/{id} 104 description: Get user by ID 105 provisionedConcurrency: 5 106 ``` 107 108 ### Step 2: Handler Implementation 109 ```python 110 # handlers/users.py 111 import json 112 import os 113 import boto3 114 from aws_lambda_powertools import Logger, Tracer, Metrics 115 from aws_lambda_powertools.metrics import MetricUnit 116 from aws_lambda_powertools.event_handler import APIGatewayRestResolver 117 118 logger = Logger(service="user-service") 119 tracer = Tracer(service="user-service") 120 metrics = Metrics(namespace="UserService", service="user-service") 121 app = APIGatewayRestResolver() 122 123 dynamodb = boto3.resource("dynamodb") 124 table = dynamodb.Table(os.environ["TABLE_NAME"]) 125 126 @app.post("/users") 127 @tracer.capture_method 128 def create_user(): 129 body = app.current_event.json_body 130 user_id = body["id"] 131 132 # Validate input 133 if not body.get("email"): 134 return {"error": "email required"}, 400 135 136 table.put_item(Item={ 137 "pk": f"USER#{user_id}", 138 "email": body["email"], 139 "name": body.get("name", ""), 140 "created_at": app.current_event.time 141 }) 142 143 metrics.add_metric(name="UserCreated", unit=MetricUnit.Count, value=1) 144 return {"id": user_id, "message": "User created"}, 201 145 146 147 @app.get("/users/<id>") 148 @tracer.capture_method 149 def get_user(id: str): 150 result = table.get_item(Key={"pk": f"USER#{id}"}) 151 user = result.get("Item") 152 if not user: 153 return {"error": "not found"}, 404 154 return {"user": user}, 200 155 156 157 @metrics.log_metrics 158 def handler(event, context): 159 # Structured logging already via powertools 160 logger.info("Processing request", extra={ 161 "path": event.get("path"), 162 "method": event.get("httpMethod") 163 }) 164 return app.resolve(event, context) 165 ``` 166 167 ### Step 3: Event Source Mapping (SQS + S3 + EventBridge) 168 ```yaml 169 # serverless.yml — event-driven functions 170 functions: 171 processOrder: 172 handler: handlers/orders.process 173 events: 174 - sqs: 175 arn: !GetAtt OrdersQueue.Arn 176 batchSize: 10 177 maximumBatchingWindowInSeconds: 5 178 - eventBridge: 179 pattern: 180 source: 181 - "custom.order" 182 detail-type: 183 - "OrderCreated" 184 - schedule: 185 rate: rate(5 minutes) 186 enabled: true 187 - s3: 188 bucket: !Ref UploadBucket 189 event: s3:ObjectCreated:* 190 rules: 191 - prefix: inbound/ 192 - suffix: .csv 193 ``` 194 195 ### Step 4: Infrastructure with Terraform 196 ```hcl 197 resource "aws_lambda_function" "api" { 198 function_name = "api-handler-${var.environment}" 199 role = aws_iam_role.lambda_exec.arn 200 handler = "main.handler" 201 runtime = "python3.12" 202 filename = "function.zip" 203 source_code_hash = filebase64sha256("function.zip") 204 timeout = 30 205 memory_size = 512 206 publish = true 207 208 environment { 209 variables = { 210 TABLE_NAME = aws_dynamodb_table.users.name 211 STAGE = var.environment 212 POWERTOOLS_SERVICE_NAME = "api-handler" 213 } 214 } 215 216 tracing_config { 217 mode = "Active" 218 } 219 220 reserved_concurrent_executions = 20 221 } 222 223 resource "aws_lambda_function_event_invoke_config" "api" { 224 function_name = aws_lambda_function.api.function_name 225 qualifier = aws_lambda_function.api.version 226 227 destination_config { 228 on_failure { 229 destination = aws_sqs_queue.dlq.arn 230 } 231 on_success { 232 destination = aws_sns_topic.success.arn 233 } 234 } 235 } 236 237 resource "aws_lambda_permission" "apigw" { 238 statement_id = "AllowAPIGatewayInvoke" 239 action = "lambda:InvokeFunction" 240 function_name = aws_lambda_function.api.function_name 241 principal = "apigateway.amazonaws.com" 242 source_arn = "${aws_apigatewayv2_api.api.execution_arn}/*/*" 243 } 244 ``` 245 246 ### Step 5: Cold Start Optimization 247 ```yaml 248 Strategies by runtime: 249 Python: 1-50ms cold starts — use AWS Lambda Web Adapter for faster responses 250 Enable provisioned concurrency for latency-critical endpoints 251 Node: 5-100ms — compile on deploy, minimize dependencies 252 Use esbuild bundler: tree-shake, reduce package size 253 Java: 500-5000ms — use SnapStart (Lambda SnapStart for Java 11+) 254 Prefer GraalVM native image (AWS provided, ~50ms cold start) 255 Go: 1-5ms — compile to native binary, almost no cold start 256 Best cold start of any interpreted/compiled runtime 257 .NET: 300-3000ms — use .NET 8 (Native AOT) for cold starts under 100ms 258 Rust: 1-3ms — compile to native, minimal cold start overhead 259 260 Provisioned concurrency: 261 - $0.0000040827 per GB-second for provisioned (vs. $0.0000133334 for on-demand) 262 - Schedule scaling: EventBridge rule to auto-scale provisioned concurrency 263 - Use for: API endpoints, latency-sensitive functions, canary deployments 264 265 Warmers (anti-pattern): 266 - CloudWatch scheduled event pinging functions every 5 min 267 - Not reliable — Lambda scales instances independently 268 - Better to use provisioned concurrency or SnapStart 269 ``` 270 271 ### Step 6: Serverless Security 272 ```yaml 273 IAM least privilege: 274 - Never use LambdaFullAccess — scope per function 275 - Use condition keys: sourceVpce, sourceIp, resourceArn, aws:SourceAccount 276 - Prefer execution role per function over shared role 277 - Rotate function URLs and API keys regularly 278 279 Secrets management: 280 - AWS: SSM Parameter Store (SecureString) or Secrets Manager 281 - Azure: Key Vault references in App Settings 282 - GCP: Secret Manager 283 - Never hardcode secrets in function code or env vars 284 - Use SDK to fetch at initialization (outside handler) 285 286 VPC considerations: 287 - Lambda in VPC: needs VPC endpoints for S3, DynamoDB, etc. 288 - No public internet by default — use NAT Gateway or VPC endpoints 289 - Adds 5-10ms cold start latency (ENI creation) 290 - Best practice: keep Lambda outside VPC unless accessing RDS/ElastiCache 291 292 Function URLs: 293 - Direct HTTPS endpoint for Lambda without API Gateway 294 - Support IAM auth or AWS_IAM auth 295 - Simple, no additional cost, but no custom domains natively 296 297 Code signing: 298 - AWS Signer for Lambda — sign and verify function code 299 - Enforce signing policies: require code signing profile 300 - Prevents tampered code from being deployed 301 ``` 302 303 ### Step 7: Serverless Observability 304 ```yaml 305 Structured logging: 306 - JSON format with correlation ID (API Gateway request ID or Lambda context) 307 - Fields: level, timestamp, service, message, request_id, duration_ms, error 308 - Use Lambda Powertools (Python, TypeScript, Java, .NET) 309 310 Distributed tracing: 311 - AWS: X-Ray with segments, subsegments, and annotations 312 - Azure: Application Insights 313 - GCP: Cloud Trace 314 - OpenTelemetry: collector as Lambda layer + OTLP exporter 315 316 Metrics: 317 - Invocations: count, errors, throttles, duration, concurrent executions 318 - Async: age of oldest message, dead-letter queue depth 319 - Business metrics: custom metrics via embedded metric format (EMF) 320 - Alert thresholds: 321 - Error rate > 1% for > 5 min 322 - Duration P99 > timeout * 0.8 323 - Throttles > 0 for > 1 min 324 - Dead-letter queue depth > 10 325 ``` 326 327 ### Step 8: Cost Management 328 ```yaml 329 Cost factors: 330 - Requests: $0.20 per 1M requests (AWS) 331 - Duration: $0.0000166667 per GB-second 332 - Provisioned concurrency: additional charge per GB-second 333 - Data transfer: Lambda → internet/$0.09 per GB, Lambda → same-region services is free 334 335 Optimization strategies: 336 - Right-size memory: more memory = proportionally more CPU (and cost) 337 - 1024 MB is the sweet spot for most Python/Node workloads 338 - Minimize runtime by optimizing code, reducing dependencies 339 - Batch SQS messages: batchSize > 1 reduces invocations 340 - Use Lambda function URLs for simple HTTP APIs (no API Gateway cost) 341 - Set reserved concurrency to prevent runaway cost from traffic spikes 342 - Use ephemeral storage /tmp for scratch files (512 MB - 10 GB) 343 - Monitor with cost allocation tags (Environment, Service, Team) 344 345 Estimated cost per 10M invocations (Python, 512 MB, 500 ms): 346 - Requests: $2.00 347 - Duration: ~$69.44 348 - Total: ~$71.44/month 349 ``` 350 351 ### Step 9: Advanced Patterns 352 ```yaml 353 Step Functions workflows: 354 - Express Workflows: high-volume, <5 min, $1 per 1000 state transitions 355 - Standard Workflows: long-running, up to 1 year, $0.025 per 1000 transitions 356 - Patterns: fan-out, parallel, wait for callback, saga (compensating transactions) 357 358 Lambda + DynamoDB Streams: 359 - Capture change data capture (CDC) events 360 - Fan out to SQS, SNS, EventBridge 361 - Handle duplicate events (idempotency via dynamodb-toolbox or idempotency key) 362 363 Lambda + WebSockets: 364 - API Gateway WebSocket API → Lambda integration 365 - $connect, $disconnect, $default routes 366 - Maintain connection IDs in DynamoDB 367 368 Lambda + EFS: 369 - Mount EFS for shared filesystem across concurrent invocations 370 - Cold start: ~1-2 seconds additional (mount time) 371 - Use for ML model inference, large reference data 372 373 Lambda response streaming: 374 - Stream responses up to 20 MB 375 - Pay-as-you-go response streaming (no API Gateway buffering) 376 - Good for large JSON, CSV generation, AI streaming 377 ``` 378 379 ## Rules 380 - Every function must have a dead-letter queue (DLQ) for async invocations. 381 - Set reserved concurrency for every production function to prevent runaway costs. 382 - Enable X-Ray (or equivalent tracing) on all functions. 383 - Use structured JSON logging with a correlation ID for traceability. 384 - Never store secrets in environment variables — use SSM/Secrets Manager. 385 - Align function memory with timeout: more memory = faster = less cost per invocation. 386 - Deploy with immutable versioning (publish = true)—never use $LATEST in production. 387 - Use Lambda versions and aliases for canary deployments (5% new, 95% old). 388 - Test cold start behavior with your runtime before production — measure and tune. 389 - Use Powertools (or equivalent) for logging, tracing, and metrics standardization. 390 391 ## Production Considerations 392 - Lambda function URLs need resource-based policy or IAM authentication — don't leave open. 393 - SQS batch processing: handle partial failures with `reportBatchItemFailures`. 394 - Lambda in VPC: create a VPC endpoint for SSM and CloudWatch Logs. 395 - SnapStart: requires Java 11+ and idempotent initialization code. 396 - Recursive loops: Lambda writing to S3 → S3 event → Lambda (infinite loop protection needed). 397 - `aws:SourceAccount` condition on Lambda resource policies to prevent confused deputy. 398 - Lambda + RDS: use RDS Proxy to avoid connection pool exhaustion. 399 - Lambda ephemeral storage default 512 MB — can increase to 10 GB for data processing. 400 - Function URL CORS: configure allowed origins, methods, and headers. 401 - Set `function_response_type=RequestResponse` for synchronous invocations. 402 - CloudFront + Lambda@Edge: 5 sec viewer-request/response, 30 sec origin-request/response. 403 404 ## Anti-Patterns 405 - No reserved concurrency — one buggy function consumes all account concurrency. 406 - Maximum memory allocation without testing — linear cost increase with minimal perf benefit. 407 - Synchronous calls between functions — use event-driven (SQS, SNS, EventBridge). 408 - Monolithic function — violates single responsibility, cold start suffers. 409 - Long timeouts (5+ min) — Lambda is for short-lived compute; use ECS/Step Functions. 410 - No error handling in async handlers — failures are silently retried then discarded. 411 - VPC for every function — unnecessary latency for functions that don't need it. 412 - Using Lambda for persistent connections (WebSocket) without proper cleanup. 413 - No idempotency handling — duplicates cause data corruption. 414 - Not testing Lambda@Edge cold start latency — adds latency to every request. 415 416 ## References 417 - references/serverless-advanced.md — Serverless Advanced Topics 418 - references/serverless-fundamentals.md — Serverless Fundamentals 419 - references/aws-lambda.md — AWS Lambda Deep Dive 420 - references/azure-functions.md — Azure Functions Configuration 421 - references/gcp-cloud-functions.md — GCP Cloud Functions 422 - references/serverless-framework.md — Serverless Framework Deployment 423 - references/step-functions.md — AWS Step Functions Workflows 424 - references/lambda-monitoring.md — Lambda Monitoring and Observability 425 - references/lambda-security.md — Lambda Security Best Practices 426 ## Handoff 427 - `devops-aws` for API Gateway, DynamoDB, SQS, EventBridge integration. 428 - `devops-observability` for AWS X-Ray and CloudWatch configuration. 429 - `devops-cicd-pipeline` for CI/CD pipelines with Lambda deployment. 430 - `devops-security` for IAM and secrets management. 431 - `devops-monitoring` for Lambda-specific monitoring dashboards. 432 433 ## Architecture Decision Trees 434 435 ### Lambda vs Fargate vs ECS 436 437 | Decision | Lambda (FaaS) | Fargate (Serverless Container) | ECS (Container Orchestration) | 438 |---|---|---|---| 439 | Execution model | Event-driven, short-lived | Long-running container | Long-running container | 440 | Max duration | 15 minutes | Unlimited | Unlimited | 441 | Cold start | Yes (<1s provisioned concurrency) | No (always warm) | No (always warm) | 442 | Scaling | Instant (per-event) | Auto-scaling (minutes) | Auto-scaling (minutes) | 443 | Cost model | Per-invocation + duration | Per-hour (vCPU + memory) | Per-hour (EC2 instances) | 444 | State | Stateless (externalize to SQS/DynamoDB) | Stateful possible | Stateful possible | 445 | Best for | Event-driven, bursty, variable | Steady API workloads | Batch, ML, GPU workloads | 446 447 ### API Gateway REST vs HTTP vs WebSocket 448 449 | Aspect | REST API | HTTP API | WebSocket API | 450 |---|---|---|---| 451 | Latency | ~50ms | ~10ms | ~50ms | 452 | Features | WAF, usage plans, API keys | JWT, CORS, cheaper | Real-time, bidirectional | 453 | Cost | Most expensive | Cheapest (~70% less) | Connection + message | 454 | Integration | Lambda, HTTP, Step Functions | Lambda, HTTP, Service Discovery | Lambda, DynamoDB | 455 | Use case | Public APIs with throttling | Microservices APIs | Chat, real-time updates | 456 457 ## Implementation Patterns 458 459 ### Terraform: Event-driven Lambda with SQS and DynamoDB 460 461 ```hcl 462 resource "aws_lambda_function" "order_processor" { 463 function_name = "order-processor-${var.environment}" 464 runtime = "nodejs22.x" 465 handler = "index.handler" 466 filename = "${path.module}/function.zip" 467 source_code_hash = filebase64sha256("${path.module}/function.zip") 468 469 memory_size = 512 470 timeout = 30 471 reserved_concurrent_executions = 50 472 473 environment { 474 variables = { 475 TABLE_NAME = aws_dynamodb_table.orders.name 476 DLQ_QUEUE_URL = aws_sqs_queue.dlq.url 477 } 478 } 479 480 tracing_config { 481 mode = "Active" 482 } 483 } 484 485 resource "aws_lambda_event_source_mapping" "sqs_trigger" { 486 event_source_arn = aws_sqs_queue.order_events.arn 487 function_name = aws_lambda_function.order_processor.arn 488 batch_size = 10 489 maximum_batching_window_in_seconds = 5 490 scaling_config { 491 maximum_concurrency = 10 492 } 493 } 494 495 resource "aws_dynamodb_table" "orders" { 496 name = "orders-${var.environment}" 497 billing_mode = "PAY_PER_REQUEST" 498 hash_key = "orderId" 499 500 attribute { 501 name = "orderId" 502 type = "S" 503 } 504 505 ttl { 506 attribute_name = "ttl" 507 enabled = true 508 } 509 510 point_in_time_recovery { 511 enabled = true 512 } 513 } 514 515 resource "aws_sqs_queue" "dlq" { 516 name = "order-processor-dlq-${var.environment}" 517 message_retention_seconds = 1209600 # 14 days 518 visibility_timeout_seconds = 30 519 } 520 ``` 521 522 ### Bash: Lambda Deployment Script 523 524 ```bash 525 #!/usr/bin/env bash 526 deploy_lambda() { 527 local function_name=$1 528 local source_dir=$2 529 530 # Install production dependencies 531 cd "$source_dir" 532 npm ci --production --ignore-scripts 533 534 # Package with esbuild for minimal bundle 535 npx esbuild index.js --bundle --minify --platform=node \ 536 --outfile=dist/index.js --external:aws-sdk 537 538 # Create deployment package 539 cd dist 540 zip -r9 "../${function_name}.zip" . 541 542 # Deploy to Lambda 543 aws lambda update-function-code \ 544 --function-name "$function_name" \ 545 --zip-file "fileb://../${function_name}.zip" 546 547 # Publish version 548 aws lambda publish-version \ 549 --function-name "$function_name" 550 551 # Update alias to point to new version 552 aws lambda update-alias \ 553 --function-name "$function_name" \ 554 --name production \ 555 --function-version "$(aws lambda list-versions-by-function \ 556 --function-name "$function_name" --query 'Versions[-1].Version' --output text)" 557 } 558 ``` 559 560 ## Production Considerations (Serverless-specific) 561 562 - Enable **provisioned concurrency** for latency-sensitive functions to eliminate cold starts 563 - Configure **Lambda Powertools** (TypeScript/Python/Java) for structured logging and tracing 564 - Set **function timeouts** realistically — 30s for APIs, 5m for batch processors, never max unless needed 565 - Implement **idempotency** in all event-driven functions (store processed event IDs in DynamoDB) 566 - Use **Lambda Extensions** for secrets caching, APM agents, and sidecar processes 567 - Enable **CloudWatch Lambda Insights** for memory profiling and cold start analysis 568 - Set **reserved concurrency** per critical function to prevent noise from other functions starving it 569 570 ### Observer Pattern for Event Handling 571 ` 572 interface EventObserver<T> { 573 onEvent(event: T): Promise<void>; 574 } 575 576 class EventBus<T> { 577 private observers: Set<EventObserver<T>> = new Set(); 578 subscribe(observer: EventObserver<T>): void { 579 this.observers.add(observer); 580 } 581 unsubscribe(observer: EventObserver<T>): void { 582 this.observers.delete(observer); 583 } 584 async emit(event: T): Promise<void> { 585 const results = Array.from(this.observers).map(o => o.onEvent(event)); 586 await Promise.allSettled(results); 587 } 588 } 589 ` 590 591 ### Configuration-Driven Approach 592 ` 593 config: 594 defaults: 595 timeout: 30s 596 retryCount: 3 597 overrides: 598 production: 599 timeout: 60s 600 retryCount: 5 601 development: 602 timeout: 300s 603 retryCount: 1 604 ` 605 606 ## Production Considerations 607 608 ### Deployment Checklist 609 - [ ] Configuration validated against schema before startup 610 - [ ] Health check endpoints registered and monitored 611 - [ ] Graceful shutdown with draining period (30s timeout) 612 - [ ] Resource limits configured (CPU, memory, file descriptors) 613 - [ ] Log level set appropriate for environment 614 - [ ] Metrics endpoint secured and exposed 615 - [ ] Rate limiting configured per-tier 616 - [ ] TLS certificates valid and auto-renewing 617 - [ ] Database migrations run as separate deployment step 618 - [ ] Feature flags ready for gradual rollout 619 620 ### Monitoring and Alerting 621 | Metric | Threshold | Severity | Action | 622 |--------|-----------|----------|--------| 623 | Error rate | > 1% over 5min | Critical | Page on-call | 624 | p99 latency | > 2s over 5min | Warning | Investigate | 625 | Throughput drop | > 50% over 1min | Critical | Check upstream | 626 | Queue depth | > 1000 over 1min | Warning | Scale consumers | 627 | Disk usage | > 85% | Warning | Clean or expand | 628 | Memory usage | > 90% heap | Critical | Restart or scale | 629 630 ## Anti-Patterns 631 632 | Anti-Pattern | Symptom | Root Cause | Solution | 633 |-------------|---------|------------|----------| 634 | Premature optimization | Complex code for no measured benefit | Guessing instead of profiling | Measure first, optimize based on data | 635 | Copy-paste reuse | Duplicate code across codebase | Lack of abstraction | Extract shared logic into libraries | 636 | Gold-plating | Features with no current requirement | Over-engineering | YAGNI — build what's needed now | 637 | Magical thinking | Assumptions without validation | Skipping error handling | Handle all failure modes explicitly | 638 639 ## Performance Optimization 640 641 ### Caching Strategy 642 Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge). 643 Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency). 644 645 ### Resource Pooling 646 - Database connections: Pool of reusable connections (HikariCP, pgBouncer) 647 - HTTP connections: Keep-alive + connection pooling for external calls 648 - Thread pool: Bounded thread pools for async task execution 649 650 ### Profiling Methodology 651 1. Establish baseline with production traffic profile 652 2. Profile CPU with sampling profiler (pprof, perf, async-profiler) 653 3. Profile memory with heap dumps and allocation tracking 654 4. Profile I/O with strace/perf trace for syscall analysis 655 5. Profile latency with distributed tracing (OpenTelemetry) 656 6. Identify bottleneck, formulate hypothesis, implement fix 657 7. Re-profile to verify improvement, repeat 658 659 ## Security Considerations 660 661 ### Threat Modeling (STRIDE) 662 - Spoofing: Identity validation, authentication 663 - Tampering: Integrity checks, digital signatures 664 - Repudiation: Audit logs, non-repudiation 665 - Information disclosure: Encryption, access control 666 - Denial of service: Rate limiting, resource quotas 667 - Elevation of privilege: Principle of least privilege 668 669 ### Supply Chain Security 670 - Dependency scanning: Snyk, Dependabot, Trivy 671 - SBOM generation: CycloneDX or SPDX format 672 - Signed commits: GPG or SSH commit signing 673 - Artifact verification: Checksum validation, signature verification 674 675 ### Secrets Management 676 - Secrets never in code — always in secrets manager (Vault, AWS Secrets Manager) 677 - Rotation policy: Rotate database credentials every 90 days 678 - Access audit: Log every secrets access, alert on anomalies 679 - Encryption at rest and in transit for all secrets 680 - Principle of least privilege: each service gets only its own secrets 681 682 ## Rules 683 - Default-deny security posture — allow only explicitly required access. 684 - All inputs validated, all outputs encoded, all errors handled. 685 - Defend in depth — multiple layers of security controls. 686 - Fail securely — errors default to safe behavior. 687 - Log security-relevant events for audit and investigation. 688 - Keep dependencies updated — automate vulnerability scanning. 689 - Design for observability from day one, not as an afterthought. 690 - Document all architectural decisions with rationale. 691 - Review code for security, performance, and correctness before merging.