AWS Course — 05 · Serverless & Events — Lambda, API Gateway, SQS, SNS, EventBridge
Post 03 scaled an EC2 fleet behind a load balancer; Post 04 added managed data behind it. Most modern AWS architectures are not all-server, all-the-time — large parts of them run as events flowing through serverless glue. This post covers the building blocks: Lambda (run code on demand), API Gateway / Function URLs (turn Lambda into HTTP), SQS (queues for decoupling), SNS (pub/sub fanout), and EventBridge (the bus for routed events). Combined, they let you build entire services with no servers to manage and bills proportional to traffic.
Series map: 00 Foundations → 01 Network First → 02 Compute & Storage → 03 Scale & Survive → 04 Managed Data → 05 Serverless & Events (this post) → 06 Workflow Orchestration → 07 Observability & Security → 08 IaC.
Learning Outcome
- Write and deploy a Lambda function (Python or Node).
- Configure Lambda memory, timeout, environment, IAM role, layers.
- Expose Lambda over HTTP via API Gateway or Function URLs.
- Use SQS for async work decoupling and back-pressure.
- Use SNS for fanout to multiple subscribers.
- Use EventBridge for cross-service event routing and SaaS integrations.
- Identify cold-start sources and mitigation patterns.
Chapter 1 — Lambda essentials
A Lambda function is a piece of code (handler) plus configuration (memory, timeout, role, env vars) that AWS runs in response to an event. Billing is per-request plus per-GB-second of execution time.
Minimal Python Lambda
1
2
3
4
def lambda_handler(event, context):
name = event.get("name", "world")
return {"statusCode": 200, "body": f"Hello, {name}!"}
Package and deploy:
1
2
3
4
5
6
7
8
9
10
11
12
13
zip -j function.zip lambda_handler.py
aws lambda create-function \
--function-name hello \
--runtime python3.12 \
--role arn:aws:iam::123456789012:role/lambda-basic-exec \
--handler lambda_handler.lambda_handler \
--zip-file fileb://function.zip
aws lambda invoke \
--function-name hello \
--payload '{"name":"Ada"}' \
--cli-binary-format raw-in-base64-out out.json
Knobs that matter
| Knob | Range | Note |
|---|---|---|
| Memory | 128 MB - 10,240 MB | CPU scales with memory — doubling memory ≈ doubles speed |
| Timeout | 1 sec - 15 min | killed if exceeded |
| Ephemeral storage | 512 MB - 10 GB at /tmp |
persists across warm invocations |
| Concurrency | up to 1000+ by default | reserved / provisioned controls |
| VPC | none (default) or attached | only attach if you need VPC resources |
Trick: memory is the most important tuning knob. Tools like Lambda Power Tuning test multiple memory sizes and recommend the sweet spot — usually faster AND cheaper than the 128 MB default.
Chapter 2 — Cold starts
When AWS provisions a fresh container for a function, the cold start cost is:
- Download the zip / image.
- Initialise the runtime.
- Run module-level / static code.
- Invoke the handler.
After the first invoke, the container stays warm a few minutes — subsequent calls skip steps 1-3.
| Runtime | Typical cold start |
|---|---|
| Python / Node | 100-500 ms |
| Go / Rust (compiled) | 50-200 ms |
| Java | 300 ms - 2 s |
| .NET | 200 ms - 1 s |
| Container image | 0.5 - 3 s |
Mitigation
- Provisioned Concurrency — keep N warm containers ready; always-on cost.
- SnapStart (Java) — snapshot init state; restore in ~1/10 the time.
- Smaller package — fewer dependencies, faster init.
- Avoid VPC unless needed — ENI attach adds 100-500 ms.
- Move heavy setup to module level — reused across warm invocations.
1
2
3
4
5
6
7
import boto3
# initialised once per cold start, reused on warm calls
s3 = boto3.client("s3")
def lambda_handler(event, context):
s3.get_object(...)
Chapter 3 — Event sources
Lambdas don't run on a schedule by default — they're invoked by event sources.
| Source | Pattern |
|---|---|
| API Gateway / Function URL / ALB | sync HTTP → Lambda → HTTP response |
| S3 | new object created / deleted → Lambda |
| EventBridge schedule | cron / rate → Lambda |
| EventBridge events | AWS API event → Lambda |
| SQS | poll a queue → Lambda |
| SNS | publish → Lambda |
| DynamoDB Streams | row change → Lambda |
| Kinesis | stream record → Lambda |
| CloudWatch Logs subscription | log line → Lambda |
| Direct invoke (SDK / CLI) | sync or async call |
Sync vs async vs polling
- Sync — caller waits for response (API Gateway, Function URL, direct
RequestResponseinvoke). - Async — Lambda returns immediately, processes in background; failures retried twice + optional DLQ (S3, SNS, EventBridge).
- Polling — Lambda runtime polls SQS / Kinesis / DynamoDB Streams in batches.
Chapter 4 — API Gateway and Function URLs
Two ways to put HTTP in front of Lambda:
API Gateway HTTP API
- Custom domain + TLS via ACM.
- Authn (JWT, Cognito, IAM, Lambda authoriser).
- Throttling, usage plans, API keys.
- Per-route Lambda integration or HTTP/private integration.
- ~USD 1 per million requests + data transfer.
Minimal wire-up: create HTTP API → add route ANY /{proxy+} → Lambda integration → deploy → get an execute-api.amazonaws.com URL.
Lambda Function URL
- One HTTPS endpoint per Lambda.
- No API Gateway in between (cheaper, simpler).
- No built-in WAF, custom domain (manual via CloudFront), or throttling.
- Best for internal tools, webhooks, prototypes.
1
2
3
4
aws lambda create-function-url-config \
--function-name hello \
--auth-type NONE
REST API (older)
The older "REST API" flavour exists for compatibility (request validation, models, X-Ray detail). For new projects in 2026, HTTP API is the right default.
Chapter 5 — SQS (Simple Queue Service)
SQS is a managed message queue. Producers send-message, consumers (often Lambda) receive-message + delete-message after success.
Two queue types:
| Type | Order | Duplicates | Use |
|---|---|---|---|
| Standard | best-effort | possible | most async work |
| FIFO | strict per group | exactly-once | order-sensitive workflows |
Lambda + SQS pattern
1
2
[API or Service A] → SQS Standard → [Lambda processes in batches]
Benefits:
- Decoupling — A returns immediately; processing runs in background.
- Back-pressure — if Lambda concurrency caps, messages sit in queue (no data loss).
- Retries — Lambda errors keep message visible; goes to DLQ after N attempts.
- Batch processing — Lambda receives up to 10 messages at once.
Visibility timeout
When a consumer receives a message, it becomes invisible to others for the visibility timeout (default 30 sec). If not deleted by then, the message reappears for another consumer. Set this to at least 2× your processing time.
Dead Letter Queue (DLQ)
Configure a DLQ on a source queue. After N receive attempts (typical: 3-5), the message moves to the DLQ for inspection. Alarm on DLQ message count > 0 — that means production has a stuck pattern.
Chapter 6 — SNS (Simple Notification Service)
SNS is pub/sub fanout — a publisher sends one message to a topic; AWS delivers a copy to every subscriber.
Subscriber types:
- SQS queue
- Lambda
- HTTPS endpoint
- Email / SMS
- Mobile push
- Kinesis Firehose
Common fanout pattern
1
2
3
4
5
6
7
8
9
[Order Service]
│ publish "order_placed"
▼
[SNS topic]
├── → SQS for inventory service
├── → SQS for email service
├── → Lambda for analytics
└── → SQS for fulfilment service
Each subscriber gets its own copy. Adding a new subscriber doesn't require changing the publisher.
Filter policies
Subscribers can filter by message attributes — only receive a subset:
1
2
{ "event_type": ["order_placed"], "region": ["ap-east-1"] }
Chapter 7 — EventBridge (the bus)
EventBridge is a richer event router than SNS:
| Trait | SNS | EventBridge |
|---|---|---|
| Fanout | yes | yes |
| Filter | by attributes | by content (JSON match) |
| Schedule | no | yes (cron / rate) |
| SaaS integrations | no | many (Datadog, Zendesk, GitHub via partner sources) |
| AWS event sources | no | every AWS service auto-publishes |
| Schema registry | no | yes |
| Latency | < 100 ms | < 500 ms |
| Cost | per published message | per matched rule |
Bus types
- Default bus — every AWS API event lands here automatically. React to "EC2 state change", "S3 object created", "RDS failover", etc.
- Custom bus — your own events.
- Partner bus — events from SaaS providers (Datadog, Auth0, Zendesk).
Targets
A rule routes matching events to targets:
- Lambda
- Step Functions
- SQS
- SNS
- Kinesis
- API destinations (any HTTPS endpoint)
- Cross-account / cross-region buses
Scheduled rules
The cleanest way to run "every 5 minutes" or "every weekday 09:00 HKT":
1
2
3
4
5
6
7
8
aws events put-rule \
--name nightly-report \
--schedule-expression "cron(0 1 * * ? *)"
aws events put-targets \
--rule nightly-report \
--targets "Id=1,Arn=arn:aws:lambda:..."
In 2026, the newer EventBridge Scheduler service is preferred for pure schedules — better scale, more options (time zones, one-time, payload customisation).
Trick: SNS for simple fanout (one source → many same-message subscribers). EventBridge for routing different events to different places, especially when AWS services are the source or you want content-based filtering. Both are cheap; pick by access pattern, not cost.
Chapter 8 — A small end-to-end serverless service
Pattern: "user uploads image → resize → notify uploader".
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Browser]
│ PUT pre-signed S3 URL
▼
[S3 bucket]
│ s3:ObjectCreated event
▼
[Lambda: resize]
│ writes thumbnail back to S3
│ publishes to SNS topic "image_processed"
▼
[SNS]
├── [Lambda: send email via SES]
└── [SQS: analytics queue]
▼
[Lambda: write event to DynamoDB]
Components:
- S3 bucket with event notification → resize Lambda.
- Resize Lambda uses Pillow (Python image lib) — package as a Lambda Layer.
- SNS topic with two subscribers.
- DynamoDB table for analytics.
- All wired with IAM roles scoped to least-privilege.
This entire architecture has zero servers to manage and bills only when an image is uploaded.
Chapter 9 — Limits worth remembering
| Limit | Value |
|---|---|
| Lambda timeout | 15 min |
| Lambda memory | 10 GB |
| Lambda zip package | 50 MB direct, 250 MB unzipped |
| Lambda container image | 10 GB |
| Lambda concurrency (default) | 1000 / region / account |
| Lambda sync payload | 6 MB |
| Lambda async payload | 256 KB |
Lambda /tmp |
10 GB |
| SQS message size | 256 KB (link to S3 for bigger) |
| SQS retention | 14 days max |
| SNS message size | 256 KB |
| EventBridge event size | 256 KB |
| API Gateway timeout | 29 sec (sync) |
Chapter 10 — When NOT to use serverless
- Long-running CPU jobs (> 15 min) — use Step Functions (Post 06), ECS Fargate, or AWS Batch.
- Steady high-throughput services where always-on EC2 / Fargate is cheaper than per-request Lambda billing.
- Cold-start-sensitive workloads where even 100 ms hurts and Provisioned Concurrency cost wipes the savings.
- Heavy WebSocket / persistent connections — use API Gateway WebSocket + Lambda or ECS.
Serverless wins when traffic is spiky, glue-shaped, or genuinely event-driven. Steady-state high-CPU workloads belong on Fargate / EC2.
Practice Exercises
Exercise 1 — Hello Lambda
Create + invoke a Python Lambda that echoes the event. Test with the CLI.
Exercise 2 — HTTP API + Lambda
Wrap Exercise 1 in API Gateway HTTP API. Hit the URL with curl. Add a POST /echo route that returns the JSON body.
Exercise 3 — S3 thumbnail trigger
Create an S3 bucket; a Lambda triggered on s3:ObjectCreated:* that, given an image, writes a half-size thumbnail to a sibling bucket. Use a Lambda Layer for Pillow.
Exercise 4 — SQS + Lambda batch
Create an SQS queue + a Lambda triggered by it. A simple producer script enqueues 100 jobs. Verify Lambda processes them in batches, set the DLQ, force a few failures and confirm they land in the DLQ after retries.
Exercise 5 — SNS fanout
Create an SNS topic; subscribe a Lambda + an SQS queue. Publish a message. Confirm both receive the message. Add a filter policy so the queue receives only messages with priority == "high".
Exercise 6 — EventBridge schedule
Create an EventBridge schedule that triggers a Lambda every 5 minutes. The Lambda fetches https://api.github.com/repos/<owner>/<repo> and writes the stargazer count to DynamoDB.
Cheat-sheet
| What | How |
|---|---|
| Create Lambda | aws lambda create-function ... |
| Invoke | aws lambda invoke --function-name X out.json |
| Tail logs | aws logs tail /aws/lambda/X --follow |
| Memory tunes CPU | bigger = faster + (often) cheaper |
| Skip VPC unless needed | avoid cold-start ENI attach |
| HTTP wrapper | API Gateway HTTP API |
| Tiny HTTP endpoint | Lambda Function URL |
| Async decoupling | SQS Standard + Lambda |
| Order-sensitive | SQS FIFO |
| Visibility timeout | ≥ 2× processing time |
| DLQ | alarm on DLQ count > 0 |
| Pub/sub fanout | SNS topic + subscribers |
| Filter subscriptions | SNS filter policy |
| Cross-service routing | EventBridge bus + rules |
| AWS-event source | EventBridge default bus |
| Scheduled job | EventBridge Scheduler |
What's next
Post 06 covers Step Functions — the state-machine service that orchestrates multiple Lambdas / API calls / human steps into a workflow with retries, branching, parallelism, and the saga pattern for distributed transactions.
References
- Lambda Developer Guide
- API Gateway docs
- SQS docs
- SNS docs
- EventBridge docs
- Serverless Land — reference patterns, samples.
Note: this post is in progress. Planned additions: WebSocket APIs, EventBridge Pipes, Kinesis vs SQS decision tree, container-image Lambdas.










