AWS / Intermediate: application service contracts / Lesson 10
Queues, events, and idempotency
Choose asynchronous boundaries by delivery, acknowledgment, ordering, failure recovery, and business identity requirements.
On this page
Lesson goals
- Explain the assumptions, responsibilities, and trade-offs of queues, events, and idempotency.
- Interpret both examples and distinguish declared intent from verified evidence.
- Diagnose the listed failures and justify the worked decisions without using a real AWS account, credential, or service.
Distinguish a command, an event, and a delivery
A command asks for work; an event reports something that happened; a delivery is one attempt to transport a message. Their identities need not be identical. SQS provides queues, SNS provides supported fan-out patterns, and EventBridge routes events through its documented buses or other integration features. Select the service mode and target contract rather than treating all messaging products as interchangeable. The first synthetic envelope separates stable business operation identity from a delivery attempt. It contains no real customer data or resource ARN and is not sent to a broker or AWS endpoint.
{"schema":"booking-request.v1","operation_id":"lab-booking-17","delivery_attempt":"lab-attempt-b","payload":{"seats":2},"classification":"public-synthetic-teaching-data"}
The operation ID remains stable across delivery attempts. The envelope is not a real customer request or an AWS publish operation and carries no credentials.
Read acknowledgment and retry semantics
A consumer receiving a message has not necessarily completed or acknowledged the business operation. In SQS, visibility and deletion have distinct roles; work can be delivered again if it is not removed under the chosen contract. Standard queues can deliver duplicates and do not guarantee the applicationโs global order. FIFO features add documented ordering and deduplication scope but do not make every external side effect exactly once. SNS, EventBridge, Lambda, and targets can each add their own retries or failure handling. Read the exact integration documentation and define who owns redelivery and terminal recovery.
Make operation identity durable
Use a stable operation key tied to the intended business action, not a new random value for every retry. A durable idempotency record should bind accepted input, state transition, and result with an appropriate atomicity and retention policy. The second simulation suppresses repeated synthetic IDs in a sequential in-memory list. It is useful arithmetic but loses state on restart and does not coordinate concurrent consumers. A database transaction, conditional write, outbox, or another application protocol may be required to connect message handling to external effects. Deleting a message before durable success can lose work; deleting afterward can leave a duplicate window.
deliveries = ["lab-a", "lab-b", "lab-a", "lab-b"]
completed = set()
for operation_id in deliveries:
if operation_id not in completed:
completed.add(operation_id)
print(len(deliveries), len(completed))
print("sequential in-memory model only")
4 2
sequential in-memory model only
Four deliveries represent two synthetic operations. The set is not durable or atomic across consumers and proves no AWS delivery guarantee.
Bound backlog and poison-message behavior
A queue buffers mismatch but does not create downstream capacity. Measure age, depth, processing time, retry volume, and useful completion, not only message count. Visibility, retention, batch size, and concurrency must fit the work and recovery objectives. A dead-letter queue is a recovery workflow boundary, not an automatic fix or permission to discard customer work. Preserve safe diagnostic context and decide whether to correct, replay, reconcile, or expire a message. Replaying an entire backlog without rate control can recreate the incident or duplicate side effects. Test schema evolution and malformed messages with synthetic data.
Verify boundaries without publishing real events
Review producer permission, broker or bus policy, encryption keys, target identity, network path, and consumer authorization separately. A successful publish response does not prove final processing or user correctness. Define monitoring, retention, ownership, and reconciliation before production adoption. No queue, topic, bus, event rule, subscription, message, redrive, or service invocation is created or executed here. The examples are offline records and a pure Python simulation. Actual delivery, ordering, throughput, and price depend on service mode, Region, current documentation, and the selected integration; no universal exactly-once or free-processing promise is made.
Common errors and fixes
Publish success is called business completion
- Why it happens
- Transport acknowledgment replaced consumer outcome.
- How to fix it
- Track durable processing and reconciliation separately.
- Prevent it next time
- Define end-to-end event status and ownership.
FIFO is assumed to make payments exactly once
- Why it happens
- Service deduplication was confused with external transaction semantics.
- How to fix it
- Use operation-level idempotency and uncertain-outcome recovery.
- Prevent it next time
- Test interruption after effect before acknowledgment.
Backlog replay recreates an outage
- Why it happens
- Recovery ignored downstream capacity and duplicate risk.
- How to fix it
- Rate-limit reviewed recovery and reconcile outcomes.
- Prevent it next time
- Rehearse poison-message and DLQ handling safely.
Check your understanding
1. A charge succeeds but message deletion fails. What can the next delivery cause?
Show worked solution
Without durable idempotency or reconciliation it can charge again. Preserve the same operation key and verify the existing outcome before repeating the external effect. Broker acknowledgment and a payment transaction are separate state transitions.
2. Why is message age often more useful than depth alone?
Show worked solution
Age can reveal that work is not completing within its deadline even when the count is small. Interpret it with arrival rate, processing time, retries, and priority. A large healthy burst and a small stuck poison-message flow need different recovery decisions.
Key takeaways
- A command asks for work; an event reports something that happened; a delivery is one attempt to transport a message.
- Use a stable operation key tied to the intended business action, not a new random value for every retry.
- Review producer permission, broker or bus policy, encryption keys, target identity, network path, and consumer authorization separately.