Containers and orchestration
Serverless event sources and retries
Functions run when events arrive from queues, storage, schedules and webhooks. Those events are delivered at least once, so every handler must tolerate duplicates.
Serverless works best when something else produces the work. A queue message, an object upload, a schedule or a webhook each triggers a function. Those triggers retry on failure, so the same event can arrive more than once. Design every handler for that from the start.
Concept
Before you start. Read delivery semantics. Serverless event sources are almost always at-least-once, which means a retry can repeat work.
Event sources
| Source | Pattern | Watch out for |
|---|---|---|
| HTTP, API Gateway, function URLs, Cloud Run URLs | Synchronous request and response | Timeouts, auth, payload size limits |
| Queues such as SQS, Pub/Sub, Cloud Tasks | Asynchronous workers that buffer work | Visibility timeouts, partial batch failures |
| Object storage such as S3 or GCS | Thumbnails, virus scans, ETL triggers | Duplicate events, so make handlers idempotent |
| Schedules such as EventBridge or Cloud Scheduler | Cron replacements | Overlap, when a run takes longer than the interval |
| Streams such as Kinesis or Kafka | Parallel consumers per shard | Poison messages and bisecting failed batches |
| Webhooks from SaaS apps | Thin adapters | Verify signatures; reply fast and queue heavy work |
For SQS and Lambda, a common rule of thumb is a visibility timeout of at least six times the function timeout. A message that reappears while the first worker is still running it is processed twice.
Walking through a fan-out
One upload can trigger a chain. An S3 PutObject starts a function. It writes a message to a queue. The queue fans out to many workers. The workers write results to a warehouse. You never provisioned a fleet for the rare spike, but you did create new failure modes: partial success, duplicates and poison messages. Each needs a dead-letter queue (DLQ), a replay tool, or an idempotent write.
An idempotent handler is one where a repeat has no extra effect. This sketch uses an in-memory dict as a stand-in for a database table with a unique key:
seen = {} # stands in for a table with a unique key on order_id
def handle(event):
order_id = event["order_id"] # a business key, not a random ID
if order_id in seen:
return "duplicate, skipped"
seen[order_id] = "charged"
return "charged"
event = {"order_id": "ord-881"}
print(handle(event))
print(handle(event))charged
duplicate, skippedIn production, store the key in a database row with a unique constraint. Memory is lost when the environment is recycled.
Common mistakes
- Assuming exactly-once. Retries happen. Make the write safe to repeat.
- Doing heavy work inside a webhook. Reply quickly and put the work on a queue.
- Letting scheduled runs overlap. If a run takes longer than the interval, runs pile up.
Check yourself
- A handler charges a card, and the platform retries the event. What happens without idempotency? Answer: the card is charged twice.
- What does a visibility timeout of at least six times the function timeout protect against? Answer: a message reappearing for another worker while the first worker is still processing it.
Key takeaways
- Serverless events are at-least-once. Plan for duplicates.
- Make writes idempotent with a business key, such as an order ID.
- Send messages that keep failing to a dead-letter queue.
- Next, concurrency and connections explains a limit that event spikes hit first.
Further learning
How Lambda processes records from streams and queues (AWS docs)Configure a Lambda event source mapping to invoke your function from queue and stream event sources, such as Amazon SQS, Kinesis, and DynamoDB.docs.aws.amazon.com Invoking Lambda asynchronously: retries and destinations (AWS docs)When you invoke a Lambda function asynchronously, Lambda places the request in a queue and returns a success response without additional information. A separate process dequeues requests and invokes your function sync…docs.aws.amazon.com Idempotency utility (Powertools for AWS Lambda)Utilitydocs.powertools.aws.dev Designing robust and predictable APIs with idempotency (Stripe)Online payment processing for internet businesses. Stripe is a suite of payment APIs that powers commerce for businesses of all sizes.stripe.comRelated
Serverless and managed runtimes
Lambda, Cloud Run and friends - what you give up, what you gain and the cost crossover versus always-on containers.
Idempotency and retries
Making operations safe to retry, with idempotency keys, deduplicating consumers and jittered backoff, so at-least-once delivery never means a double charge.
Delivery semantics
The three promises a messaging system can make (at-most-once, at-least-once, exactly-once) and why the real choice is when the consumer says "done".