# EventBridge and Step Functions

Two serverless building blocks for **event-driven** (choreography) and **workflow** (orchestration) designs (`distributed-systems/message-brokers/11-event_driven_architecture`, `distributed-systems/fundamentals/08-distributed_transactions`).

## 1. EventBridge: an Event Bus With Routing Rules

```json
{
  "source": "petpal.orders",
  "detail-type": "OrderPlaced",
  "detail": { "orderId": "o-17", "customerId": "c-4", "total": 4599, "currency": "EUR" }
}
```

- **Event buses**: the `default` bus (AWS service events like "EC2 instance state change"), **custom buses** for your application events, **partner buses** (SaaS: Stripe, Zendesk, Datadog…).
- **Rules** match events with **event patterns** and send them to up to 5 **targets** (Lambda, SQS, SNS, Step Functions, API destinations — any HTTPS endpoint, Kinesis, another bus, ECS tasks…):

```json
{
  "source": ["petpal.orders"],
  "detail-type": ["OrderPlaced"],
  "detail": { "total": [{ "numeric": [">", 10000] }], "currency": ["EUR"] }
}
```

- **Input transformers** reshape the event for each target; **DLQs** and retry policies per target (retries up to 24 h).
- **Archive & replay**: keep events and replay them into the bus (rebuild a read model, recover from a consumer bug).
- **Schema registry** and discovery generate code bindings for event types.
- **EventBridge Pipes**: point-to-point source (SQS, Kinesis, DynamoDB Streams, Kafka) → filter → enrich (Lambda/Step Functions/API) → target, without glue Lambdas.
- **EventBridge Scheduler**: one-time or recurring schedules (cron/rate, time zones) invoking any target — replaces "cron Lambda" patterns.

**EventBridge vs SNS vs SQS**: EventBridge = content-based routing with rich filtering, many targets, SaaS integration, archive/replay, ~$1 per million events, a bit more latency; SNS = high-throughput fan-out pub/sub with simpler filtering; SQS = durable queue for one consumer group (`07-sqs_and_sns/`). Common combination: EventBridge rule → SQS queue per consumer (buffering + retries).

## 2. Step Functions: Workflows as State Machines

A **state machine** (defined in Amazon States Language, JSON/YAML, or visually in Workflow Studio) orchestrates steps with built-in retries, error handling, timeouts and state:

```json
{
  "StartAt": "ReserveStock",
  "States": {
    "ReserveStock": {
      "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": { "FunctionName": "reserve-stock", "Payload.$": "$" },
      "Retry": [{ "ErrorEquals": ["States.TaskFailed"], "MaxAttempts": 3, "BackoffRate": 2, "JitterStrategy": "FULL" }],
      "Catch": [{ "ErrorEquals": ["OutOfStock"], "Next": "NotifyOutOfStock" }],
      "Next": "ChargeCard"
    },
    "ChargeCard": {
      "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": { "FunctionName": "charge-card", "Payload.$": "$" },
      "Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "ReleaseStock" }],
      "Next": "ShipOrder"
    },
    "ReleaseStock": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Parameters": { "FunctionName": "release-stock", "Payload.$": "$" }, "Next": "OrderFailed" },
    "ShipOrder": { "Type": "Task", "Resource": "arn:aws:states:::sqs:sendMessage", "Parameters": { "QueueUrl": "https://sqs…/shipping", "MessageBody.$": "$" }, "End": true },
    "NotifyOutOfStock": { "Type": "Pass", "End": true },
    "OrderFailed": { "Type": "Fail", "Error": "PaymentFailed" }
  }
}
```

State types: `Task` (do work), `Choice` (branch), `Parallel`, `Map` (iterate — **Distributed Map** processes millions of S3 items with high concurrency), `Wait` (seconds or until a timestamp — free waiting, unlike Lambda), `Pass`, `Succeed`, `Fail`.

**Integrations**: 200+ AWS services called directly (`arn:aws:states:::dynamodb:putItem`, `ecs:runTask.sync`, `glue:startJobRun.sync`) — no Lambda glue. Patterns: request/response, `.sync` (wait for job completion), **`.waitForTaskToken`** (pause until an external system or human calls `SendTaskSuccess` with the token — approvals, callbacks).

| | **Standard** workflows | **Express** workflows |
|---|---|---|
| duration | up to 1 year | up to 5 minutes |
| semantics | exactly-once step execution, full history | at-least-once (async) / at-most-once (sync) |
| pricing | per state transition (~$25 per million) | per request + duration (cheap at high volume) |
| use | business processes, sagas, human approval | high-volume event processing, IoT, streaming transforms |

## 3. Choreography + Orchestration Together

A common shape: services publish domain events to **EventBridge** (loose coupling between bounded contexts); **inside** a context, a **Step Functions** workflow orchestrates a multi-step transaction with compensations (a saga), emitting events at the end. Events for "tell others"; workflows for "do these steps reliably in order".

## Under the Hood: How Step Functions Remembers Where It Is

Each Standard workflow execution is a durable log of **history events** (`TaskStateEntered`, `TaskScheduled`, `TaskSucceeded`, `ExecutionSucceeded`…) persisted by the service. The orchestrator processes the state machine as a series of transitions: on each event it evaluates the current state's definition, applies `InputPath`/`Parameters`/`ResultSelector`/`ResultPath`/`OutputPath` to shape the JSON passed along (max 256 KB — store large payloads in S3), schedules the next task, and records it. Because state lives in the service, not in your code, a workflow can wait a week for a callback, survive deployments, and retry a failed step with backoff without keeping any compute running. Retries are scheduled by the service using the `Retry` rules (`IntervalSeconds`, `BackoffRate`, `MaxDelaySeconds`, `JitterStrategy`), and `Catch` routes errors — including timeouts and task-token heartbeats — to compensation states.

![Services publish events to an EventBridge bus where rules filter and route them to Lambda, SQS or Step Functions, with archive and replay; a Step Functions state machine orchestrates reserve, charge and ship steps with retries and catches that run compensations](diagrams/01-events-and-workflows.svg)

## Common Pitfalls

1. **Lambdas that call other Lambdas synchronously in chains** — use Step Functions.
2. **Waiting inside Lambda** (sleep/poll) instead of `Wait` states or task tokens.
3. **Large payloads through state** (256 KB limit) — pass S3 pointers.
4. **No DLQ on EventBridge targets** — failed deliveries vanish after retries.
5. **Overly broad event patterns** — every consumer receives everything, coupling returns.
6. **Express workflows for steps that must not run twice** (at-least-once).

## Quick Reference

```
EventBridge: bus → rule (event pattern) → ≤5 targets · input transformer · DLQ + retries · archive/replay · Pipes · Scheduler
Step Functions: ASL states (Task/Choice/Parallel/Map/Wait) · Retry + Catch · direct service integrations · .sync · .waitForTaskToken
Standard (≤1 year, exactly-once, per transition) vs Express (≤5 min, high volume, cheap)
events between contexts, workflows within a context (sagas)
