The Lambda worker
After this you can answer: How does a message in a queue become a Lambda call, and what is a partial batch failure?
Picture it
Section titled “Picture it”flowchart TB Q["SQS jobs queue"] -->|"poll"| M["event source mapping<br/>batch 10, max 5 at once"] M -->|"call with batch"| F["worker Lambda<br/>256 MB, 10 s"] F -->|"batchItemFailures: [ids]"| M M -->|"delete the rest"| QHow it works
Section titled “How it works”- Poll. AWS’s pollers long-poll the jobs queue and collect up to 10 messages.
- Call. They call the function with the batch. At most 5 batches run at the same time
(
maximumConcurrency). - Handle one by one. For each message: is the job already done (DynamoDB)? If not, send the email (SES), then record it as done.
- Answer. The handler returns
{ batchItemFailures }, listing only the failed message ids. Before answering, it hides each failed message for 10 s, 40 s or 120 s. - Delete the rest. Because the mapping has
ReportBatchItemFailures, Lambda deletes every message not in the list. The failed ones come back later.
In MiniTickets
Section titled “In MiniTickets”| Worker (email) | Tickets | |
|---|---|---|
| Function | minitickets-dev-worker | minitickets-dev-tickets |
| Entry point | lambda.handler | ticket-lambda.handler |
| Memory / timeout | 256 MB / 10 s | 512 MB / 30 s |
| Batch / parallel | 10 / 5 | 1 / 2 |
Both are container images (arm64) from the worker repository, and both run outside the VPC: they
call only public AWS APIs, so they need no NAT gateway. A Lambda has ONE execution role, used by the
Lambda service and our code alike; trust: lambda.amazonaws.com.
Measured locally (under the Lambda runtime emulator): the first start took 302 ms, a warm batch 23 ms, and a failed message came back after 10.0 s.
Who may assume Worker Lambda execution role: Worker Lambda
What it may do:
| On | Actions | Policy | Why only this |
|---|---|---|---|
| Jobs SQS queue | sqs:ReceiveMessagesqs:DeleteMessagesqs:ChangeMessageVisibilitysqs:GetQueueAttributes | identity ReadJobsQueue createWorkerRole | The event source mapping receives and deletes with this role; the code's backoff changes the visibility. No SendMessage, no DLQ: SQS itself moves failed messages. |
| Processed-jobs table | dynamodb:GetItemdynamodb:PutItem | identity ProcessedJobsTable createWorkerRole | isDone is a GetItem and markDone a conditional PutItem. No Scan, Query or Delete: TTL deletes for free. |
| SES email identitiesour domain identity ARN and the test-address identity ARN | ses:SendEmailif ses:FromAddress = no-reply@minitickets.theversehub.in | identity SendBookingEmails createWorkerRole | The policy restricts the sender to our configured address; it does not constrain email content. |
| CloudWatch log groups/minitickets/dev/worker:* only | logs:CreateLogStreamlogs:PutLogEvents | identity WriteWorkerLogs createWorkerRole | No logs:CreateLogGroup: Pulumi creates the group with a 7-day retention. |
See it in AWS
Section titled “See it in AWS”Lambda → Functions → minitickets-dev-worker → Configuration → Triggers, and Monitor.
aws lambda list-event-source-mappings --function-name minitickets-dev-worker
The mapping: infra/src/jobs/queue-trigger.ts → createQueueTrigger;
the batch: apps/worker/src/batch.ts → handleBatch.
Break it
Section titled “Break it”| Symptom | Cause | Where to look |
|---|---|---|
| Failed messages disappear after a normal return | ReportBatchItemFailures is missing, so Lambda ignores the failed ids and deletes the whole batch | Lambda → Triggers |
| Messages move slowly; Throttles above 0 | The account’s available concurrency is exhausted | Lambda → Monitor; check the current account quota |
| “Task timed out after 10.00 seconds” | A slow SES or DynamoDB call; undeleted messages become visible when their visibility timeout expires | /minitickets/dev/worker |
Say it in an interview
Section titled “Say it in an interview”Follow-ups
Section titled “Follow-ups”Why maximumConcurrency and not reserved concurrency?
With only a reservation, the pollers can fetch more batches than may run. Those calls are
throttled, and repeated receives can send healthy messages to the DLQ. maximumConcurrency
caps this queue’s concurrent invocations at five. It reserves no capacity: other functions can
still exhaust the account quota and throttle it.
Why outside the VPC?
Inside, it would need a NAT gateway or VPC endpoints to reach SES, SQS and DynamoDB. It never talks to Postgres: the message carries everything the email needs.
Container image or zip?
One image pipeline for all three apps and a 10 GB uncompressed image limit. A larger deployment can add initialization work; measure cold starts rather than assuming one format is faster.
Can good messages still be retried?
Yes. An uncaught exception or timeout fails the whole invocation, even with partial batch reporting. Some emails may already have been sent. The completed-job check skips recorded jobs; a send before its completion record can still be repeated.
Advanced: Details: the tickets Lambda and both roles
The tickets function signs up to four tickets with an HMAC key it reads from Secrets Manager at run
time, writes QR PNGs under tickets/ in S3 and the ticket items to DynamoDB. It uses the queue’s
visibility timeout as its retry delay. The worker’s log group is /minitickets/dev/worker, not
Lambda’s default /aws/lambda/…, so the 7-day retention applies.
AWS documents the partial batch response rules
and the 10 GB image limit.
Its pricing page explains request and duration billing.
Who may assume Tickets Lambda execution role: Tickets Lambda
What it may do:
| On | Actions | Policy | Why only this |
|---|---|---|---|
| Tickets SQS queue | sqs:ReceiveMessagesqs:DeleteMessagesqs:GetQueueAttributes | identity createTicketRole | Consume the tickets queue through the event source mapping. |
| Tickets table | dynamodb:GetItemdynamodb:PutItemdynamodb:UpdateItem | identity createTicketRole | Reserve, write and complete the ticket items of one booking. |
| Ticket assets buckettickets/* only | s3:PutObject | identity createTicketRole | Write the QR PNGs. It cannot read or touch posters. |
| Ticket signing secret | secretsmanager:GetSecretValue | identity createTicketRole | Read the HMAC key that signs tickets. The api never gets this key. |
| CloudWatch log groups/minitickets/dev/tickets:* only | logs:CreateLogStreamlogs:PutLogEvents | identity createTicketRole | Write its own log lines, nowhere else. |
Checkpoint
Section titled “Checkpoint”Answer these without scrolling up. If one feels hard, reread that section.
- What does the event source mapping do for us?
- What does the handler return, and what does Lambda do with it?
- What happens without
ReportBatchItemFailures? - Why does the worker run outside the VPC?
- Name two differences between the worker and the tickets Lambda.
Redraw it from memory: jobs queue → event source mapping (batch 10, max 5) → worker → batchItemFailures → delete the rest
Try this: on the map, select the worker Lambda execution role and see what its statements light up
Read this book online: https://book.theversehub.in/