mantis-matrix-integration – Blame information for rev 1

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