Event-driven architecture on AWS
Event-driven architecture integrates services through asynchronous events rather than synchronous calls. A producer emits a fact; a router delivers it; consumers react. Nobody waits for anybody, which is what makes the components scale and fail independently.
What an event is
Section titled “What an event is”An event is a record of something that has already happened, at a specific moment, in a specific system. Three properties follow from that definition and they do most of the work:
- It is immutable. It records a fact about the past. It cannot be revoked, only superseded by a later event.
- It is a notification, not a command. It says what changed, when, and with what data. It does not say what anybody should do about it — that is the consumer’s decision.
- It is broadcast, not addressed. Any number of interested consumers can react: updating their own state, starting a workflow, or maintaining a projection. The producer does not know who they are, which is precisely the coupling that has been removed.
The last point is the one that changes designs. When a producer names its consumers, adding a consumer is a change to the producer. When it emits an event, it is not.
The services involved
Section titled “The services involved”| Service | Role |
|---|---|
| AWS Lambda | Serverless compute; runs the logic that reacts to an event |
| Amazon EventBridge | Event bus; routes events to targets by content-based rules, across accounts and from SaaS providers |
| AWS Step Functions | Orchestrates multi-step workflows, holding state, branching and retries |
| Amazon SQS | Queues and buffers events, absorbing bursts and decoupling producer rate from consumer rate |
| Amazon SNS | Pub/sub fan-out to subscribers, including queues, functions, HTTP endpoints and people |
| Amazon API Gateway | Front door for events originating outside the system |
| Amazon DynamoDB | Serverless data store; its streams turn writes into events |
| Amazon S3 | Object storage that emits events on bucket actions |
Choosing between EventBridge, SNS and SQS is a common sticking point. In outline: SQS is point-to-point buffering with at-least-once delivery and dead-letter support; SNS is fan-out with attribute- and content-based filtering and very high subscription counts; EventBridge is routing with content-based rules, schema validation, archive and replay, and the widest set of native AWS targets and third-party sources. Overlaps are substantial — for the quotas and trade-offs that usually settle it, see the integration pattern comparison matrix.
Orchestration and choreography
Section titled “Orchestration and choreography”These are the two ways to make several services accomplish one thing, and most real systems use both.
Orchestration — AWS Step Functions. A central workflow holds the state and calls each step in turn. Use it when the process has decision points, needs retries with defined semantics, must be idempotent, or has to be visible as a whole while it runs. The trade-off is that the workflow knows about all the steps, so the coupling that has been removed between services reappears inside the state machine — which is usually the right place for it.
Choreography — Amazon EventBridge. No central coordinator. Each service reacts to events and emits its own; the process is an emergent property of the rules. Use it when producers and consumers should evolve independently, when the set of consumers is expected to grow, and when no single component needs to know the whole flow. The trade-off is that no single component knows the whole flow, which is exactly why tracing and correlation IDs stop being optional.
A common and effective combination: choreograph between bounded contexts, orchestrate within one.
A worked flow
Section titled “A worked flow”An order-processing system built this way:
- Submission. The front end calls API Gateway, which invokes a Lambda function. The
function validates the request and publishes an
order.createdevent to EventBridge. - Routing. EventBridge rules match the event and deliver it to the targets that care — here, a Step Functions state machine that decides whether the customer is new.
- Fulfilment. The state machine runs the order workflow: update customer data, write to
DynamoDB, process the order, and emit an
order.processedevent when it finishes. - Notification. A rule on that event invokes a function that pushes the update to the waiting client over a WebSocket connection.
Nothing in step 1 knows about step 4. Adding a fraud check, an analytics consumer or an email notification means adding a rule and a consumer, not modifying the order service.
Practical guidance
Section titled “Practical guidance”- Define the event schema deliberately and version it. An event contract is a public interface, and it is harder to change than an API because you cannot see who is reading it. The EventBridge schema registry and CloudEvents are both reasonable starting points.
- Design for at-least-once delivery. Every consumer must be idempotent. This is not negotiable and it is not something you can add later.
- Give every event a correlation ID at the edge and propagate it. Without one, a choreographed system is not debuggable.
- Configure dead-letter queues and retry policies on every target from the outset. The default failure mode of an asynchronous system is silence.
- Watch the payload sizes. EventBridge caps an event entry at 256 KB. Larger payloads belong in S3 with a pointer in the event.
Reference
Section titled “Reference”- Serverless Land — AWS’s collection of event-driven patterns
- Amazon EventBridge User Guide