Propagate a Request Deadline

Independent timeouts multiply latency. An end-to-end deadline turns the remaining caller budget into a system-wide constraint.

Backend · TypeScript

Request Deadline Propagation

Downstream work inherits the caller’s remaining time; it does not receive a new budget.

async function withDeadline<T>(parent: AbortSignal, remainingMs: number, work: (signal: AbortSignal) => Promise<T>) {
  if (remainingMs <= 0) throw new Error('deadline exceeded')
  const signal = AbortSignal.any([parent, AbortSignal.timeout(remainingMs)])
  return work(signal)
}

await withDeadline(request.signal, remainingMs, signal => fetch(url, { signal }))

Invariant: No downstream operation outlives the remaining end-to-end budget.

Use when: Downstream work must not outlive the caller’s latency budget.

Why this boundary matters

Independent per-hop timeouts accumulate and leave orphan work after callers depart. One deadline bounds the complete synchronous call tree.

Failure policy

BoundaryAction
Budget remainsPass the smaller remaining budget downstream
No useful budget remainsFail before starting more work
Child operation times outAbort it and propagate a typed deadline outcome
Caller cancelsCancel all owned downstream work immediately
Background work must surviveDetach it through a durable queue, not the request context

Trade-offs

Deadlines prevent orphan work and cap tail latency, but budgets that are too tight create self-inflicted failures. Per-hop timeouts must shrink from one end-to-end deadline rather than accumulate independently.

Decision rule: Propagate a deadline across synchronous work; move work to a durable asynchronous boundary when it must outlive the caller.

Further reference

Browse all engineering snippets · Read about retry amplification

>