Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

System Design (High-Level Design)  Module 5 – APIs and communication patterns

Synchronous vs asynchronous communication

When a caller should wait for the answer and when it should hand the work to a queue, a status URL or a callback, and what each choice costs.

  • Intermediate
  • 20 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0 and quickjs 0.32.0
  • By MySmartCoPilot
Free intro, Pro: 5 of 20 minutes free
Free: Waiting couples the caller to every callee. With a pass: the other 8 sections and 3 interview answers, about 15 minutes.

What you will learn

  • Calculate the availability of a chain of synchronous calls
  • Apply the asynchronous request-reply pattern with 202 Accepted
  • Compare polling and callbacks by the requests a second they cost
  • Protect a queue consumer against redelivery, poison messages and reordering
  • Decide for each operation whether the caller should wait for the result

Before you start

What you’ll learn · Before you start

What you will learn

  • Calculate the availability of a chain of synchronous calls
  • Apply the asynchronous request-reply pattern with 202 Accepted
  • Compare polling and callbacks by the requests a second they cost
  • Protect a queue consumer against redelivery, poison messages and reordering
  • Decide for each operation whether the caller should wait for the result

Before you start

On this page

Checkout waits on five services in turn, each up 99.9 % of the time, so it fails whenever any one of them is down: about 216 minutes of failed orders a month. A call is synchronous when the caller waits for the answer before it does anything else, and asynchronous when it hands the work over, to a queue or to a job that reports back, and carries on.

Wait when the caller cannot continue without the answer and the callee is fast and dependable, as with reading a price or authorising a payment. Hand the work over when it is slow, can safely happen later, or must not take the caller down when it fails, as with emails, reports and search indexing. A sound default for user-facing writes: keep the user waiting only until the change is durably committed, and do everything after the commit asynchronously.

Waiting couples the caller to every callee

A synchronous call creates temporal coupling: The dependence a synchronous call creates between a caller and its callee: both must be up, and fast, at the same moment. Along a chain of such calls, availabilities multiply and latencies add.: the caller and the callee must both be up, and fast, at the same moment. The coupling compounds along a chain, because every service the request waits on is a hard dependency: A part that every request needs, so the service fails whenever it does. Hard dependencies are in series, and each one lowers the availability the whole service can reach. More in “Availability maths: nines, series and parallel”. If checkout waits on five services in turn and each is up 99.9 % of the time, an order succeeds only when all five are, so its availability is the product of theirs when they fail independently:

Availability of a chain of synchronous calls Python · chain-availability/chain_availability.py
"""How available is a request that waits on a chain of services? Each service is up 99.9 % of the time, and
failures are assumed independent (shared causes such as one database make the real numbers worse)."""

MINUTES_A_MONTH = 30 * 24 * 60
EACH = 0.999

print("services the request waits on   available   down a month")
for n in range(1, 7):
    up = EACH**n
    print(f"{n:>29}   {up:>9.2%}   {(1 - up) * MINUTES_A_MONTH:>6.0f} min")

# Asynchronous after the commit: the request needs only the API and the queue; the workers behind the queue may
# be down without failing it (its work waits instead).
up = EACH**2
print(f"\nAPI and queue only (workers behind the queue)   {up:.2%}   {(1 - up) * MINUTES_A_MONTH:.0f} min")

Output

services the request waits on   available   down a month
                            1      99.90%       43 min
                            2      99.80%       86 min
                            3      99.70%      129 min
                            4      99.60%      173 min
                            5      99.50%      216 min
                            6      99.40%      259 min

API and queue only (workers behind the queue)   99.80%   86 min

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 chain_availability.py

Five services at 99.9 % leave checkout at 99.5 %: about 216 minutes of failed orders a month instead of 43. Their latencies add up along the chain too, so every callee’s slow moments become the shopper’s wait. Asynchronous communication breaks the chain at the commit: the request needs only the API and a durable queue, and the work behind the queue waits, instead of failing, while its service is down. Follow one order through both designs during a 30-second email outage:

Interactive · step by step One order during a 30-second email outage, wired two ways Step through the same order twice, first waiting on all five services, then waiting on two and queueing the rest.
One order during a 30-second email outage, wired two ways, step 8 of 8. Showing Shopper, Checkout API (waits on 2 calls), Queue (empty), Inventory, Payments, Email (back up), Loyalty, Analytics. In focus: Email.ShopperCheckout APIwaits on 2 callsQueueemptyInventoryPaymentsEmailback upLoyaltyAnalyticsorder placed

The drawing shows the whole scene; its 8 steps are listed below.

Every step as text
  1. Design A, an order arrives. A shopper places an order. In design A, the checkout API calls all five services in turn and answers only when every one of them has answered.
  2. Two calls succeed. Inventory reserves the stock and payments authorises the card. The order still waits, because three more calls are in its path.
  3. Email is down. The email service is in the middle of its 30-second outage, so the third call times out, and the whole order fails with it although the stock and the money were fine.
  4. Five dependencies, one product. Each service is up 99.9 % of the time, and an order needs all five at once, so checkout can take orders 0.999 to the fifth power of the time, 99.5 %, about 216 minutes of failed orders a month.
  5. Design B, two calls, then commit. Now the same order in design B. Checkout calls inventory and payments, whose answers the order needs, commits the order and puts one message on a queue.
  6. The order succeeds. The shopper gets a confirmed order at once. Email, loyalty and analytics are no longer in the order's path, so their outages cannot fail it.
  7. The work waits, not fails. The email worker cannot send the receipt while its service is down, so the message stays in the queue. The outage costs a delay, not an order.
  8. Email is back. When the email service returns, the queue delivers the message and the receipt goes out about 30 seconds late. Loyalty and analytics take theirs at their own pace.

With a queue in front of the email service, a 30-second email outage becomes 30 seconds of late emails instead of 30 seconds of failed orders. Both designs side by side, and three ways to learn the outcome:

Checkout wired two ways: waiting on five services in turn, or waiting on two, committing, and queueing the rest.Synchronous: waits on all fiveAsynchronous after the commitShopperCheckout APIInventory, payments,email, loyalty,analyticsShopperCheckout APIInventory,paymentsOrdersdatabaseQueueEmail, loyalty,analytics workersplace order5 calls in turn;any failurefails the orderplace order1, 23: commit4: order placedlater

The same checkout, synchronous throughout or asynchronous after the commit

Text description of the diagram

The figure has two panels, one under the other.

  1. Synchronous: the order waits on all five. A shopper places an order with the checkout API, which calls five services one after another: inventory, payments, email, loyalty and analytics. If any of the five fails, the order fails.
  2. Asynchronous after the commit. The shopper places an order with the checkout API, which calls only inventory and payments (steps 1 and 2, needed before the order can be committed) and commits the order to the orders database (step 3). An "order placed" message then goes from the committed order to a queue (step 4). The email, loyalty and analytics workers take messages from the queue later, at their own pace, so their outages delay that work instead of failing the order.
Waiting, polling or being called back
Criterion SynchronousPolledCalled back
Caller waits for The resultA 202 and a status URLAn acknowledgement only
Worker is down The request failsThe work waitsThe work waits
Outcome arrives In the responseWhen a poll finds it finishedWhen the callback or event arrives
Hard parts Timeouts, retries, tail latencyPoll traffic, status storage, expiryA reachable endpoint, signatures, duplicates
When to choose The caller cannot go on without the answer, and the callee is fastSlow jobs for clients that cannot receive calls, such as browsersSlow jobs for servers that can receive calls, and events after a commit

The ways to communicate, by name:

  • Synchronous request-response: the caller sends a request and blocks until a reply or a timeout.
  • asynchronous request-reply: An API pattern for work that outlives a request: the server answers 202 Accepted at once, with the URL of a status resource that the client polls until the work is done.: the server answers 202 Accepted at once, with a status URL the client polls.
  • Callbacks: the server calls the client back, for example through a webhook, when the work is done.
  • Queues: a producer leaves a message, and one of several consumers processes it when it is ready.
  • publish-subscribe: A messaging style in which a producer publishes an event and every subscriber receives its own copy and acts on it in its own time, without the producer knowing who listens.: a producer publishes an event, and every subscriber receives it and acts in its own time.

Asynchronous communication has its own costs: it trades an outage for a delay, and adds duplicate deliveries, messages out of order and failures that nobody is waiting to see.

Key idea

A caller that waits needs every callee up at that moment, so availabilities multiply along the chain; work that can follow the commit belongs behind a queue, where an outage becomes a delay.

Checkpoint

Check: How waiting couples a caller to its callees

  1. Question 1 of 2 Checkout waits on four services in turn, each up 99.9 % of the time, and their failures are independent. What share of the time can checkout take orders?

    Type a number.

    A hint

    An order needs all four at the same moment, so multiply their availabilities.

    Show the answer: Question 1 of 2

    Answer: 99.6 % (anything from 99.59 to 99.61 counts)

    0.999⁴ ≈ 0.996, so checkout is up about 99.60 % of the time, as the program's table shows for four services: about 173 minutes of failed orders a month instead of 43 for one service.

  2. Question 2 of 2 Checkout now commits each order after inventory and payments and puts the rest on a queue. The email service goes down for 30 seconds. What happens to the orders placed in those 30 seconds?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: They succeed, and their emails go out about 30 seconds late

    With a queue after the commit, an outage behind the queue turns into a delay of that work, not a failure of the request: 30 seconds of outage become 30 seconds of late emails.

Measuring the coupling over one simulated day Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • The asynchronous request-reply pattern, step by step
  • Polling or callbacks: the cost, in requests a second
  • Failure drill: duplicates, a poison message and reordering
  • Four questions choose per operation
  • Practise: a consumer that survives redelivery
    • A consumer that survives redelivery and reordering
  • Interview questions
    • Checkout calls inventory, payments, fraud scoring, email and loyalty services synchronously, one after another. Last week the email provider was down for 40 minutes and no orders could be placed. Redesign which calls stay synchronous, and say what the shopper sees now.
    • Design the API that exports a merchant's transactions as a file. Small exports finish in 2 seconds, large ones take 20 minutes. Walk through every request and response from the first click in the browser to the download, including the failures.
    • After loyalty points and address changes moved to a queue with several consumers, some customers got double points and some addresses went back to an old value. Explain both bugs from the queue's delivery guarantees, then fix them without giving up parallel consumers.
  • Key takeaways

3 diagrams · 3 runnable examples (Python) · 1 exercise with sample tests · 3 interview answers · about 51 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Read a complete sample first: Design a unique ID generator

Terms in this lesson

asynchronous request-reply
An API pattern for work that outlives a request: the server answers 202 Accepted at once, with the URL of a status resource that the client polls until the work is done.
publish-subscribe
A messaging style in which a producer publishes an event and every subscriber receives its own copy and acts on it in its own time, without the producer knowing who listens.
temporal coupling
The dependence a synchronous call creates between a caller and its callee: both must be up, and fast, at the same moment. Along a chain of such calls, availabilities multiply and latencies add.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.