Intermediate12 min

Dependency Exhaustion

Running out of a finite shared resource — connections, threads, file handles — under load.

By the end of this lesson, identify finite resources that get exhausted and bound their use.

How deep?
How the pieces actually move.

Every system runs on finite pools: database connections, HTTP client connections, worker threads, file descriptors, memory. Under load — or when one dependency slows down and holds resources longer — a pool empties. New work then blocks or fails, and the exhaustion of one shared pool can take down features that have nothing to do with the slow dependency.

One slow call drains the pool

One slow call drains the pool

  1. A slow dependency holds pooled connections longer, exhausting the shared pool and blocking unrelated requests.
flowchart LR
  slow[Slow dependency] --> hold[Connections held longer]
  hold --> pool[Pool exhausted]
  pool --> other[Unrelated requests blocked]

Controls: size pools deliberately, set timeouts so nothing holds a resource indefinitely, use bulkheads to give critical paths their own pools (so one slow dependency can't drain everyone's), apply circuit breakers to stop feeding a dead dependency, and shed load when saturated. Monitor pool utilization and wait time, not just latency.

Resource pool exhaustion

Trigger
A finite pool (connections/threads/handles) is drained under load or by a slow dependency.
Symptom
New requests block or fail; unrelated features degrade together.
Blast radius
Everything sharing the exhausted pool.
Mitigation
Timeouts, bulkheads/pool isolation, circuit breakers, load shedding, right-sized pools.
How does a bulkhead limit exhaustion damage?

By isolating pools per dependency/feature, so one slow dependency drains only its own pool and can't starve unrelated work.

Exhaustion often coincides with clocks and timeouts misbehaving. What subtle failure comes from disagreeing clocks?

Next: Clock Skew →