Skip to content

Instantly share code, notes, and snippets.

@christeredvartsen
Created September 25, 2020 09:12
Show Gist options
  • Save christeredvartsen/7776e40a0102a571c35a9fc892164a8c to your computer and use it in GitHub Desktop.
Save christeredvartsen/7776e40a0102a571c35a9fc892164a8c to your computer and use it in GitHub Desktop.
Simple retry strategy for Guzzle 7 when encountering "429 Too Many Requests" errors

Simple retry strategy for Guzzle 7

APIs might implement rate limiting, and if they do your clients might experience 429 Too Many Requests responses with a Retry-After header, informing your client how long it should wait before making the next request. And being good internet citizens we should all implement support for this in our API clients.

Guzzle includes a retry middleware class that can be used to handle this.

The implementation in this gist is a PoC, so feel free to build upon it, and comment if you think something should be added / removed.

<?php declare(strict_types=1);
require 'vendor/autoload.php';
use Psr\Http\Message\{RequestInterface, ResponseInterface};
use GuzzleHttp\{Client, HandlerStack, Middleware, RetryMiddleware};
$maxRetries = 3;
$decider = function(int $retries, RequestInterface $request, ResponseInterface $response = null) use ($maxRetries) : bool {
return
$retries < $maxRetries
&& null !== $response
&& 429 === $response->getStatusCode();
};
$delay = function(int $retries, ResponseInterface $response) : int {
if (!$response->hasHeader('Retry-After')) {
return RetryMiddleware::exponentialDelay($retries);
}
$retryAfter = $response->getHeaderLine('Retry-After');
if (!is_numeric($retryAfter)) {
$retryAfter = (new DateTime($retryAfter))->getTimestamp() - time();
}
return (int) $retryAfter * 1000;
};
$stack = HandlerStack::create();
$stack->push(Middleware::retry($decider, $delay));
$client = new Client(['handler' => $stack]);
// ...
{
"require": {
"guzzlehttp/guzzle": "^7.1",
}
}
@ignas2526
Copy link

Works great. There's a small bug:
The return RetryMiddleware::exponentialDelay($retries);
should be return RetryMiddleware::exponentialDelay($retries) * 1000;

@christeredvartsen
Copy link
Author

christeredvartsen commented Apr 8, 2022

@sowmiksudo
Copy link

Thanks for your quick gist

@kudamhazo
Copy link

Appreciate the gist! Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment