Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Deadlines
HLD

Deadlines

Propagating time budgets across service hops — so distributed work gives up together instead of orphaning itself.

The Orphaned Work Problem

Timeouts exist per hop, but nobody tells downstream services when the caller already gave up:

 client timeout: 800ms
 └─► gateway (own timeout 900ms)
     └─► pricing svc (timeout 5000ms!) starts expensive calc
         ... finishes at 4000ms, writes result, publishes event
 
 nobody is listening. 100% wasted compute — and the write
 may have side effects! every hop needs to know:
 "the caller abandons at T; don't bother after that"

The Deadline Header

The fix: carry a deadline timestamp through every call:

 request headers:
   X-Request-Deadline: 2026-08-24T10:00:00.800Z   (absolute)
 or
   grpc-timeout: 700m                             (gRPC does this natively)

 each service on receipt:
   remaining = deadline - now()
   own budget = min(remaining × share, own default)
   pass deadline - consumed onward to children

 chain behavior: everyone gives up TOGETHER at T,
 no orphaned computation, no zombie writes

Deadline vs Timeout

TimeoutDeadline
ScopeSingle callWhole request journey
ValueDuration (“500ms”)Absolute time
Propagates?NoYes, through all hops
Answers”How long do I wait here?""Is anyone still listening?”

Implement deadlines as propagated absolute times; per-hop timeouts become min(local_default, remaining_deadline).

Cancellation: The Active Half

Knowing the deadline is half of it; acting is the other:

 context cancellation (Go ctx, gRPC, React Query-style tokens):
   caller aborts → cancellation signal propagates
   → in-flight queries cancelled at DB level
   → loops check token between iterations
   → partial work discarded BEFORE committing side effects

 without propagation hooks, deadlines only stop NEW work;
 running work must poll/subscribe to learn it's unwanted

Budget Allocation Patterns

 reserve-for-response: keep ~10% of budget for your own reply
 proportional-split:   divide remaining among N children
 critical-path-first:  give the serial dependency most of the budget
 
 anti-pattern: each hop sets child timeout = FULL original budget.
 5 hops × 1s "budgets" → worst case 5s for an 800ms request.
 budgets shrink as they flow; never reset mid-chain

Observability Payoff

 log/metric per hop: deadline_remaining_ms
 traces show where budgets die:
   pricing used 600ms of its 250ms slice ← instant diagnosis
 
 deadline telemetry turns "requests feel slow sometimes"
 into a precise map of which stage overspends when

Interview Framing

Multi-service designs earn points with one sentence: “deadlines propagate via headers; each hop’s timeout is bounded by remaining budget.” The follow-up probes orphaned side effects — connect to idempotency keys and transactional outbox. Candidates treating timeouts as purely local config miss the distributed-systems question hiding underneath.

My Private Notes

Notes are auto-saved locally to this device.