4 use GuzzleHttp\Promise\PromiseInterface;
5 use GuzzleHttp\Promise\RejectedPromise;
7 use Psr\Http\Message\RequestInterface;
8 use Psr\Http\Message\ResponseInterface;
11 * Middleware that retries requests based on the boolean result of
12 * invoking the provided "decider" function.
23 * @param callable $decider Function that accepts the number of retries,
24 * a request, [response], and [exception] and
25 * returns true if the request is to be
27 * @param callable $nextHandler Next handler to invoke.
28 * @param callable $delay Function that accepts the number of retries
29 * and [response] and returns the number of
30 * milliseconds to delay.
32 public function __construct(
34 callable $nextHandler,
35 callable $delay = null
37 $this->decider = $decider;
38 $this->nextHandler = $nextHandler;
39 $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
43 * Default exponential backoff delay function.
49 public static function exponentialDelay($retries)
51 return (int) pow(2, $retries - 1);
55 * @param RequestInterface $request
56 * @param array $options
58 * @return PromiseInterface
60 public function __invoke(RequestInterface $request, array $options)
62 if (!isset($options['retries'])) {
63 $options['retries'] = 0;
66 $fn = $this->nextHandler;
67 return $fn($request, $options)
69 $this->onFulfilled($request, $options),
70 $this->onRejected($request, $options)
74 private function onFulfilled(RequestInterface $req, array $options)
76 return function ($value) use ($req, $options) {
86 return $this->doRetry($req, $options, $value);
90 private function onRejected(RequestInterface $req, array $options)
92 return function ($reason) use ($req, $options) {
100 return \GuzzleHttp\Promise\rejection_for($reason);
102 return $this->doRetry($req, $options);
106 private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
108 $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
110 return $this($request, $options);