Setting a five-second timeout on a slow dependency feels like protection and is not: with twelve PHP-FPM workers and a dependency taking five seconds, twelve concurrent requests occupy the entire pool for five seconds and the site is down.
// bounds one call
$client = new Client(['timeout' => 5.0, 'connect_timeout' => 1.0]);
// bounds how many can be in flight at once — the missing half
if (! $this->semaphore->acquire('payments', 4)) {
throw new TooBusy();
}
The timeout bounds the damage per request; the pool is the resource that runs out. A connect timeout much shorter than the read timeout is the cheap first move — a dependency that is down usually refuses or hangs on connect, which can be detected in a second rather than five. The full answer is a bulkhead: a limit on concurrent calls per dependency, so one slow upstream cannot take every worker.