Async Patterns vs Sync: When Each Wins
Async is sold as performance medicine; the right answer is more nuanced. Sync wins more often than people think.
Sync vs async basics
Sync and async are different request shapes, not different intensities of the same shape. The choice changes how the system fails as much as how it performs.
- Sync. Request, response, in the same call; client waits for completion; failure surfaces immediately.
- Async. Request, queue, eventual processing, notification; client returns fast; failure is a queue or DLQ event.
- Latency vs throughput. Sync optimises for low time-to-result; async optimises for high sustained throughput.
- Failure surface. Sync errors are easy to debug; async errors require queue introspection and idempotency reasoning.
Four-criteria split
- 1. Time-to-result tolerance.
- 2. Throughput requirements.
- 3. Failure-handling needs.
- 4. Operational complexity tolerance.
Queue patterns
The queue is the central abstraction in async systems. Its shape decides what kinds of failure the system can recover from gracefully.
- Sync simplicity. One call, one response; debuggable with curl; failure mode is a single error returned to the caller.
- Async throughput. Decouples producer from consumer; absorbs traffic spikes that would topple a sync system.
- Spike resilience. Queue absorbs the spike; consumer drains at sustainable rate; backpressure handled by queue depth.
- Eventual-completion failure. 'Job will eventually finish, or not'; observability must surface stuck or dead-lettered work.
Operational cost
Async is sold as performance medicine but bills as operational complexity. Budget the cost honestly before choosing it.
- Queue infrastructure. Kafka, SQS, RabbitMQ; runtime, monitoring, capacity planning.
- Consumer monitoring. Per-consumer lag, error rate, processing-time dashboards.
- DLQ handling. Dead-letter queue plus replay tooling; the policy for how DLQ items return to the main queue.
- Idempotency. Every consumer must be idempotent; this is design work, not a config flag; budget 1-2 engineer-quarters per major async path.
Antipatterns
- Async for everything. Operational complexity exceeds value.
- Sync where async would help. Backpressure cascades.
- Async without DLQ. Lost work.
What to do this week
Three moves. (1) Apply this pattern to your slowest production endpoint. (2) Measure p99 before/after. (3) Document the win and ship the runbook so the team can reproduce.