PHP cookbook · Intermediate
Call external APIs with timeouts and retries in PHP
Call a flaky third-party API without hanging PHP-FPM workers or amplifying outages.
Approach
Use Guzzle or Symfony HttpClient with explicit connect and total timeouts, retry only idempotent requests on transient failures (connection errors, 429, 502–504) with exponential backoff and jitter, honor Retry-After, and cap attempts. Map failures to domain exceptions.
Solution
<?php
declare(strict_types=1);
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
$stack = HandlerStack::create();
$stack->push(Middleware::retry(
function (int $retries, RequestInterface $req, ?ResponseInterface $res, ?Throwable $e): bool {
if ($retries >= 3 || !in_array($req->getMethod(), ['GET', 'HEAD', 'PUT', 'DELETE'], true)) {
return false;
}
return $e instanceof GuzzleHttp\Exception\ConnectException
|| in_array($res?->getStatusCode(), [429, 502, 503, 504], true);
},
function (int $retries, ?ResponseInterface $res): int {
$retryAfter = (int) ($res?->getHeaderLine('Retry-After') ?: 0);
return $retryAfter > 0 ? $retryAfter * 1000 : (int) (100 * 2 ** $retries + random_int(0, 100)); // ms
},
));
$client = new Client([
'base_uri' => 'https://api.example.com/',
'handler' => $stack,
'connect_timeout' => 2.0,
'timeout' => 5.0,
'headers' => ['Accept' => 'application/json'],
]);
$rates = json_decode((string) $client->get('rates/USD')->getBody(), true, flags: JSON_THROW_ON_ERROR);
Pitfalls
- Default Guzzle timeout of 0 (wait forever).
- Retrying POSTs that aren't idempotent (double charges).
- Retries multiplying load during an outage — add a circuit breaker for critical dependencies.
Variations
- Symfony HttpClient's
RetryableHttpClientwithGenericRetryStrategy. - Laravel HTTP client:
Http::timeout(5)->retry(3, 200)->get(...).
Further reading: Guzzle: Request options
Reference: https://docs.guzzlephp.org/en/stable/request-options.html#timeout
More PHP recipes
- Add CSRF protection to PHP forms
- Add health check endpoints to a PHP app
- Add structured logging with request IDs in PHP
- Build a secure password reset flow in PHP
- Cache expensive queries with Redis in PHP
- Handle file uploads securely in PHP
- Implement rate limiting in a PHP API
- Make a PHP payment endpoint idempotent