Designing Idempotent Workers for Data Pipelines
Practical patterns for safer ingestion, retries, and medallion-style processing on AWS.
A practical checklist for making ingestion, transformation, and reporting pipelines easier to operate.
A data pipeline can be green on every dashboard and still be lying to you. The orchestration job succeeded, the Lambda didn't error โ and the report is a day stale, missing a partition, and full of duplicate rows. Observability for pipelines isn't "did the job run"; it's "can I trust the data it produced." ๐
Freshness is the signal users feel first, because they make decisions on the data. Every dataset should expose three things: when it was last updated, which source produced it, and whether any expected partition is late. Treat a late partition like a failed request โ it's a user-facing incident, even when the job "succeeded."
flowchart LR
S[Sources] --> I[Ingest]
I --> T[Transform]
T --> R[(Reporting tables)]
R --> D[Dashboards]
I -.freshness / lineage.-> M[Signals]
T -.quality checks.-> M
R -.row counts.-> M
M --> A[Actionable alert]A job can finish cleanly and still emit incomplete or wrong data. Run data-quality checks beside orchestration health, not instead of it:
| Check | Catches |
|---|---|
| Schema drift | A source silently added or renamed a column |
| Row-count delta | A partial load or a runaway duplicate |
| Null-sensitive fields | A broken join or missing upstream field |
| Duplicate keys | Non-idempotent re-runs |
Green orchestration plus a red quality check should still page someone.
Observable pipelines keep enough source identity to trace a bad report back to its input after transformation. Carry source object keys, event IDs, extraction timestamps, and batch IDs through each layer. When an analyst flags a wrong number, you want to answer "which input produced this?" in minutes, not spend an afternoon reverse-engineering it.
An alert that just says "pipeline failed" makes someone go digging. A useful one names the owner, the dataset, the failure class, and the next action:
{
"dataset": "gold.daily_active_users",
"owner": "data-platform",
"failure_class": "freshness",
"detail": "partition dt=2026-07-24 is 6h late",
"next_action": "check AppFlow source export schedule"
}Now the on-call engineer knows whether this is freshness, quality, permissions, source availability, or compute โ before opening a single log.
Practical patterns for safer ingestion, retries, and medallion-style processing on AWS.
How to stop losing (and duplicating) events when your service writes to a database and Kafka at the same time.
When hand-wiring main.go stops scaling, and what Fx's graph resolution and lifecycle ordering buy you in return.