Skip to content

Trade-offs · Foundations

Synchronous vs asynchronous calls

When a caller should wait for the answer and when it should hand work off, the numbers that decide, and what breaks with each choice.

Asked at: SDE-1SDE-2

The decision

In a synchronous call, the caller waits until the work is finished. In an asynchronous (async) call, the caller hands the work over and continues at once. The work finishes later, often through a queue of waiting jobs. The choice sets how long the user waits and how many requests your servers can hold. It also decides what happens when a helper service is slow.

Choose synchronous when

  • The user needs the result now, such as an order number or a price.
  • The next step needs the work to be done. A payment must be accepted before you confirm the order.
  • The step makes a promise. When the screen says "Order placed", the order must be saved.
  • A failure must stop the request, such as a wrong card.
  • The work is fast. A step of 20 ms is not worth a queue.

Choose asynchronous when

  • The user does not need the result in the response, such as an SMS or an email.
  • A late result does no harm. Seconds or minutes are fine.
  • The work is slow, or it calls a service that is often slow.
  • The work is safe to repeat, because a queue can deliver a job twice.
  • The load comes in peaks. A line of waiting jobs smooths them.

The numbers that change the answer

Two formulas decide most cases.

  • Requests in progress = requests per second x seconds each one takes.
  • A server can hold only as many requests as it has workers.

Worked example at Indian scale. A food app at 8 pm. Assumptions: five steps after payment: save the order (200 ms), SMS (1,200 ms), email (800 ms), points (250 ms) and a message to the restaurant (250 ms). The server has 200 workers. The peak is 100 orders per second for 600 seconds. Adding a message to a queue takes 5 ms.

DesignTime per requestRequests in progressShare of 200 workers
All synchronous200 + 1,200 + 800 + 250 + 250 = 2,700 ms100 x 2.7 = 270135%
Save order, queue 4 jobs (SMS, email, points, restaurant)200 + 4 x 5 = 220 ms100 x 0.22 = 2211%

The synchronous design cannot carry the peak. The async design uses 11% of the workers.

Now the price of async. The restaurant job has its own queue and workers. Assumption: the SMS, email and points jobs need 1.2 + 0.8 + 0.25 = 2.25 seconds of worker time per order. Ninety workers serve them.

  • Work rate = 90 / 2.25 = 40 orders per second.
  • Backlog grows by 100 - 40 = 60 per second. After 600 seconds: 60 x 600 = 36,000 jobs.
  • The last SMS waits 36,000 / 40 = 900 seconds, which is 15 minutes.

With 180 workers, the work rate is 80 per second. The backlog is (100 - 80) x 600 = 12,000. The last wait is 12,000 / 80 = 150 seconds.

What breaks with each choice

  • Synchronous: one slow helper holds a worker for each waiting request. When all 200 workers are busy, the server cannot answer even requests that do not need the helper. Timeouts add up along a chain of calls. Fix: set a timeout on every call.
  • Asynchronous: results come late, jobs can run twice, and jobs can finish out of order. A growing backlog hides a failure. If the app saves the order but fails to add the job, the job is lost. Fix: make each job safe to repeat, watch the age of the oldest message, not only the backlog size, and scan recent orders for missing jobs.
  • The async caller does not learn if the work succeeded. Return status 202 Accepted with a job number, so the app can ask later.

What it costs

  • Sync is the cheapest to build and to debug. You pay when load grows.
  • Async adds a queue to run, a worker pool, retry rules and job status screens. Plan for days of work (rough guess).
  • Moving one step from sync to async later is easy if the step is already a separate function. It is hard if the next step reads its result.

How each level answers

SDE-1: Sync means the caller waits. Async means the caller hands the work over and continues. A queue holds the waiting jobs.

SDE-2: I keep the order save in the request because it is a promise. I move the SMS and email to a queue, because the user does not need them now and the helper is slow.

Senior: All five steps take 2,700 ms. At 100 orders per second that is 270 requests in progress against 200 workers, so the server fails. With the save only, it is 22. The risk is a backlog: 90 workers give a 15-minute SMS delay at the peak. The fallback is 180 workers, which gives 150 seconds.

Staff: I ask which delays the business accepts. A late SMS is fine, but a late restaurant message loses orders, so it gets its own queue and a tighter alert. I move steps out one at a time, with a switch to go back, and measure request time and the age of the oldest message. One team owns the queue and its alerts.

Say it in the interview

I would keep the order save in the request because it is the promise, and queue the SMS, email and points. This cuts the request from 2,700 ms to 220 ms. The cost is delay and repeated jobs, so I make jobs safe to repeat and alert on the age of the oldest message.

Common mistakes

  • Putting every step in the queue. The promise to the user must be saved before the screen confirms.
  • Saying "async makes the system faster". The response is faster. The total work is the same and finishes later.
  • Watching only the backlog size. A short backlog with an old message means the queue is stuck.
  • Calling a helper with no timeout. One stuck helper can fill all your workers.

Sources

Understand the trade-off. Practise explaining your choice.

In an AI mock interview, the interviewer can push on a choice like this one: it changes a number and asks if your answer still holds.