1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
<?php namespace GuzzleHttp;
use GuzzleHttp\Promise\PromiseInterface; use GuzzleHttp\Promise\RejectedPromise; use GuzzleHttp\Psr7; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface;
/** * Middleware that retries requests based on the boolean result of * invoking the provided "decider" function. */ class RetryMiddleware { /** @var callable */ private $nextHandler;
/** @var callable */ private $decider;
/** * @param callable $decider Function that accepts the number of retries, * a request, [response], and [exception] and * returns true if the request is to be * retried. * @param callable $nextHandler Next handler to invoke. * @param callable $delay Function that accepts the number of retries * and [response] and returns the number of * milliseconds to delay. */ public function __construct( callable $decider, callable $nextHandler, callable $delay = null ) { $this->decider = $decider; $this->nextHandler = $nextHandler; $this->delay = $delay ?: __CLASS__ . '::exponentialDelay'; }
/** * Default exponential backoff delay function. * * @param $retries * * @return int */ public static function exponentialDelay($retries) { return (int) pow(2, $retries - 1); }
/** * @param RequestInterface $request * @param array $options * * @return PromiseInterface */ public function __invoke(RequestInterface $request, array $options) { if (!isset($options['retries'])) { $options['retries'] = 0; }
$fn = $this->nextHandler; return $fn($request, $options) ->then( $this->onFulfilled($request, $options), $this->onRejected($request, $options) ); }
private function onFulfilled(RequestInterface $req, array $options) { return function ($value) use ($req, $options) { if (!call_user_func( $this->decider, $options['retries'], $req, $value, null )) { return $value; } return $this->doRetry($req, $options, $value); }; }
private function onRejected(RequestInterface $req, array $options) { return function ($reason) use ($req, $options) { if (!call_user_func( $this->decider, $options['retries'], $req, null, $reason )) { return \GuzzleHttp\Promise\rejection_for($reason); } return $this->doRetry($req, $options); }; }
private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null) { $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
return $this($request, $options); } }
|