Architecture Tradeoff Explorer

Every comparison answers the same five questions — use when, avoid when, complexity, operational cost, failure modes — so the decision is about your constraints, not the fashion of the year.

The caller waits, or the caller hands the work to a broker and moves on. Synchronous is simpler and consistent; asynchronous decouples rate and availability at the price of eventual state, duplicates and an invisible backlog.

Synchronous call
Request/Response vs Event-Driven
Asynchronous (queue)
Message Queues
Use whenThe caller needs the result to respond, the dependency chain is short, and strong consistency is required — a price, an authorisation, a stock check.The work can happen later, is retryable (idempotent), and the producer's rate or availability must not depend on the consumer — emails, thumbnails, exports, fan-out.
Avoid whenThe dependency is external and slow at the tail and the caller could accept "pending"; every waiting request holds a thread.The handler is not idempotent, the caller needs read-your-writes, or nobody will watch queue depth and oldest-message age.
ComplexityLow: a call with a timeout; add retry budget and a breaker when the dependency is external.Medium: a broker, ack/visibility timeout, retry with backoff, dead-letter queue, idempotent consumers, a status path for the user.
Operational costLatency and availability compose: the caller inherits the callee's p99 and its outages.A broker to run and monitor; consumer scaling by depth; the failure mode moves from "slow response" to "silent backlog".
Failure modesCascading timeouts, exhausted thread pools, retry amplification through the chain.Backlog growing for hours unnoticed, stale state shown to users, lost consequence when the event was published after the commit without an outbox, duplicates on redelivery.
Data flowA → B → A, in the requestA → broker → B, later; result surfaces via a status entity, callback or event
ConsistencyStrong: the caller sees the effect on returnEventual: the effect lands after the response; the entity carries a pending state
ObservabilityLatency histograms and error rates per callQueue depth, oldest-message age, consumer lag, DLQ size