Lambda and Serverless
7 pages · ~5 min✓ Reviewed
Builds on RDS and DynamoDB.
Lambda Execution Model
1. What Lambda Is
- One function run per event, in a managed execution environment
- Pay per request and per GB-second
- No servers to manage
2. Handler and Lifecycle
python
def handler(event, context): left = context.get_remaining_time_in_millis() return {"left_ms": left}
event = trigger JSON; context = request ID, time left, memory
- Initdownload code, start runtime, run outside-handler code
- Invokerun handler
- Shutdownenvironment freed
- Warm environment is reused, so Init is skipped
- Code outside the handler runs once per environment
3. Invocation Types
| Type | Caller waits | Retries | Example |
|---|---|---|---|
| Synchronous | yes | the caller | API Gateway |
| Asynchronous | no, queued | Lambda, twice | S3, SNS |
| Event source mapping | no, polled | queue or stream | SQS, Kinesis, DynamoDB Streams |
Cold Starts, Timeouts and Memory
1. Cold vs warm
- Cold start = new environment, runs Init first
- Warm start = reuses an environment, skips Init
- Hits: first call after idle, scale-out bursts, new deployments
2. Reduce cold starts
- Smaller packages
- Node, Python, Go start faster than JVM
- Init SDK clients outside the handler
- SnapStart: Java, Python, .NET
- Provisioned concurrency keeps environments warm
python
s3 = boto3.client("s3") # module level, once per environment
3. Memory and timeout
| Limit | Value |
|---|---|
| Lambda timeout | 3 s default, 15 min max |
| REST API | 29 s default, raise by quota |
| HTTP API | 30 s max |
- Memory 128 to 10,240 MB; CPU scales with it
- More memory = shorter duration, often lower cost
- Tune with Lambda Power Tuning
Timeout trap
A 15 min function behind a default API fails at 29 s.
Triggers and API Gateway
1. Triggers
| Trigger | Invocation |
|---|---|
| API Gateway | sync |
| S3, SNS, EventBridge rules and schedules | async |
| SQS, Kinesis, DynamoDB Streams | polling |
2. API Gateway types
| HTTP API | REST API | WebSocket API | |
|---|---|---|---|
| Pick | cheaper, lower latency, simpler | full feature set | two-way connections |
| Has | JWT auth | API keys, usage plans, validation, WAF, caching | persistent sockets |
3. Proxy and auth
- Event = the whole request
- Return
{statusCode, headers, body}; body is a string - Gateway does auth (IAM, Cognito, Lambda authorizer), throttling, CORS, stages
python
import json def handler(event, context): return {"statusCode": 200, "headers": {"Access-Control-Allow-Origin": "*"}, "body": json.dumps({"ok": True})}
CORS
In proxy mode the function must return the CORS headers too.
4. Interview Point
- HTTP or REST? HTTP for simple cheap APIs; REST for API keys, usage plans, WAF, caching
- Proxy response shape?
{statusCode, headers, body}, body a string - Auth before Lambda? IAM, Cognito or Lambda authorizer; rejected calls never reach it
SQS, SNS and EventBridge
1. SQS Buffers Work
- Pull queue that buffers work; Lambda polls it
- Batch size: default 10, up to 10,000 standard, 10 FIFO
- Failed message returns after the visibility timeout
2. SNS and EventBridge
- SNS: push fan-out, one publish reaches Lambda, SQS, HTTP, email
- Filter policies: each subscriber gets only matching messages
- EventBridge: rule patterns on a bus route events to targets
- Also cron/rate schedules, SaaS and AWS events, schema-based filtering
3. Choosing
| Model | Use for | |
|---|---|---|
| SQS | Pull queue | Decouple, absorb spikes |
| SNS | Push fan-out | Broadcast |
| EventBridge | Bus + rules | Route by content |
- Publish
- SNS topic
- SQS queues
- Lambda
Combine them
SNS fan-out into SQS queues: broadcast plus per-consumer buffering and retries.
When Not to Use Serverless and Common Mistakes
1. Poor Fit
| Need | Why not Lambda | Use |
|---|---|---|
| Job over 15 min | 15 min timeout cap | containers |
| Steady high load | per-request cost adds up | containers or EC2 |
| Low latency | cold starts | containers |
| Large or GPU | 10,240 MB cap, no GPU | EC2 |
2. Common Mistakes
- Function triggers itself, or two trigger each other: set reserved concurrency and a billing alarm
- DB connection per invocation exhausts the DB: use RDS Proxy or a pool outside the handler
/tmpand globals may vanish: keep state in S3 or DynamoDB- Retries and SQS deliver at least once: make handlers idempotent
python
conn = pymysql.connect(host=PROXY_HOST) def handler(event, context): with conn.cursor() as cur: cur.execute("SELECT * FROM orders WHERE id = %s", (event["id"],)) return cur.fetchone()
connect once per environment, outside the handler
3. Remember
Idempotent
The same event twice must give the same result. Use an idempotency key, such as the order ID.
Serverless Cheat Sheet
1. Limits
| Limit | Value |
|---|---|
| Function timeout | 15 min |
| Memory | 128 MB to 10,240 MB |
| API Gateway timeout | 29 s |
| Async retries | 2 |
| SQS batch | 10 default, up to 10,000 standard, 10 FIFO |
2. Invocation and Cold Starts
| Invocation | Who retries |
|---|---|
| Sync | the caller |
| Async | Lambda, then DLQ or destination |
| Polling | queue or stream redelivers |
- SnapStart: Java, Python, .NET
- Provisioned concurrency
- Small packages
- Init clients outside the handler
3. Pick the Service
- HTTP API: simple, low-cost APIs
- SQS: buffer work
- SNS: fan out
- EventBridge: route and schedule
4. Interview Point: Order Flow
- Flow: API Gateway → Lambda → SNS → SQS queues → workers
- Spikes: SQS buffer plus reserved concurrency
- Duplicates: visibility timeout 6x function timeout, idempotent handler
- Poison: DLQ with maxReceiveCount
Check yourself
A function has a 15 min timeout behind a default REST API. A job takes 40 s. What does the caller see?
- A 504 at 29 s: the API Gateway integration timeout, not the function timeout
- Fix: return 202 and queue the work (SQS)
Spot the bug: a function triggered by S3 uploads writes its output into the same bucket.
- Each output fires the function again: a recursive loop and runaway cost
- Fix: separate bucket or prefix filter, reserved concurrency, billing alarm
A proxy handler returns {"statusCode":200,"body":{"ok":true}}. Why does the client get a 502?
- In proxy integration body must be a string, so a dict is a malformed response
- Fix:
json.dumpsthe body