Synchronous vs Asynchronous Communication
- Pradeep P
- 3 days ago
- 3 min read
Series: Modern System Design · Layer 2 — Communication
Layer 2 · Post 3 of 10
← Previous: gRPC → Next: Message Queues
Layer 2 — Communication · Post 18 of 88
Synchronous calls wait for an answer. Asynchronous calls hand the work off and continue. That choice shapes latency, coupling, and failure.
What you'll learn
What sync and async mean between services (not just in your programming language)
How each pattern fails, and what the user feels
A simple rule for picking one in a design
The idea in one minute
Synchronous: Service A calls Service B and blocks until B replies (or the timeout fires). REST and unary gRPC are usually this.
Asynchronous: Service A sends a message (to a queue, a log, a bus) and gets on with life. B processes it later. A may never wait for B's done.
Sync couples time: A is only as fast and as available as B. Async couples the message: A and B must agree on a payload, not on being up at the same instant.
Why it matters
Almost every why is checkout slow / flaky story is this choice.
If placing an order synchronously calls payments, inventory, email, analytics, and fraud, the user waits for the slowest and the flakiest. One timeout and the whole click fails — even if the card already charged (you now have the distributed-system bug from Post 1).
If placing an order writes OrderPlaced and returns 201, email and analytics can happen in the background. The user gets a fast confirmation. You accepted eventual side effects.
Neither is always right. Money movement often needs a synchronous authorized / declined before you promise the package. Welcome email almost never does.
How it works
Sync path
User → API → Payments → (wait) → API → User
Good when the user must see the result now (login, pay, search).
Cost: latency adds. Failure is contagious (circuit breakers exist because of this — Layer 3).
Async path
User → API → DB + enqueue SendEmail → User (done), then a worker talks to the email provider.
Good when work is slow, bursty, or optional for the click.
Cost: the user might see we're on it before it is true. You need retries, dead-letter queues, and idempotency so the worker can crash safely.
In-process async is not the same
async/await in one service still often makes a synchronous HTTP call. The thread might not block, but the request still waits. Don't confuse language async with architecture async.
A simple example
Food-delivery Place order:
Must be sync: Is this restaurant open? Can we charge this card?
Should be async: SMS to the restaurant, push to the driver pool, you earned 10 points, dump to the warehouse.
If the SMS vendor is down, dinner should still be ordered. If the card is declined, it should not.
Common mistakes
Async for everything because it sounds scalable. Then support cannot tell the user if the order exists, and you debug with check the queue.
Sync chains four deep. A → B → C → D, each 50 ms p99 plus GC pauses. The user feels 200 ms+ and four ways to 500.
Fire-and-forget without a queue. A sendEmail inside the API process dies when the pod dies. A queue remembers.
Calling async event-driven and stopping. Events need a bus, a schema, and owners. Coming posts: queues, Kafka, pub/sub, EDA.
How this shows up in real systems
Banks: authorize sync; ledger posting and statements often async.
Uber / DoorDash style: matching can be async with a wait screen; the tap still needs a fast write.
Your API gateway: timeouts on sync routes; 202 Accepted on async jobs with a status URL.
Interview: for each hop, say does the user wait? If no, draw a queue.
Recap
Sync waits. Simple, coupled in time, failure spreads.
Async hands off. Fast clicks, extra machinery, eventual side effects.
Pick per user need, not per fashion.
The usual box for the handoff is a message queue.
Series: Modern System Design · Layer 2 — Communication
Layer 2 · Post 3 of 10
← Previous: gRPC → Next: Message Queues



Comments