Timeouts: The Resilience Setting Almost Everyone Forgets
Most outages begin with a request that never times out. Here's how to set deadlines that stop one slow dependency from taking down your whole system.
Every engineer has watched a dashboard during an outage — request counts climbing, latency graphs going vertical, and almost nothing coming back. More often than you'd expect, the root cause isn't a crash or a bad deploy. It's a request that waited, patiently and indefinitely, for a dependency that was never going to answer. The fix is the least glamorous line in your codebase: the timeout.
A missing timeout is an unbounded promise
When you call a database, an external API, or a payment gateway without a timeout, you're making an open-ended promise: I'll wait as long as it takes. That sounds reasonable until you remember that threads, connections, and memory are finite. Every stalled request holds a slice of those resources hostage.
Under normal conditions you never notice. Under load — exactly when you can least afford it — those held resources run out. A healthy service that depends on one slow service inherits its slowness, then passes it upstream to its own callers. This is how a single degraded component quietly takes down an entire system.
Know which timeout you're actually setting
"Set a timeout" is more ambiguous than it sounds. Most network calls have several distinct clocks:
- Connection timeout — how long to wait while establishing the connection.
- Read (or response) timeout — how long to wait for data once connected.
- Overall deadline — the total budget for the whole operation, retries included.
The dangerous part: many popular HTTP clients ship with a connection timeout but no read timeout by default. The connection succeeds, the server accepts your request, and then it simply never responds — and you wait forever. Check the defaults for every client library you use. Assume nothing.
Budget deadlines, don't guess them
A common mistake is picking timeout values based on how slow the dependency might get. Flip it around. Set timeouts based on how long the caller can actually afford to wait.
Work backward from the user. If a customer-facing request must answer within two seconds, an internal call inside it cannot be allowed five. Better still, propagate the remaining budget down the chain — each layer passes along the time it has left, so nobody keeps working on a request the user already gave up on.
A timeout isn't a guess about how long something takes. It's a statement about how long you're willing to wait.
They work as a team
Timeouts rarely act alone. They're the foundation that makes other resilience patterns possible:
- A timeout cuts off the call that's gone quiet.
- A retry with backoff and jitter gives a transient failure another chance.
- A circuit breaker stops you from hammering a dependency that's clearly down.
Without timeouts, the other two can't even function — they never receive the signal that something has gone wrong.
The takeaway
Spend an afternoon auditing every outbound call your service makes — databases, queues, third-party APIs, internal services — and confirm each one has an explicit, sensible deadline. It's tedious, unglamorous work. It's also the cheapest insurance you'll ever buy against a 3 a.m. page.
Build with Abati Technology
We build software that ships — WhatsApp API, developer tools, POS, and mobile apps. Let's talk about your project.
Get in Touch →