PluginProbe
Depicter — Popup & Slider Builder / trunk
Depicter — Popup & Slider Builder vtrunk
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / modules / GuzzleHttp / RetryMiddleware.php

RetryMiddleware.php in Depicter — Popup & Slider Builder trunk, at modules/GuzzleHttp/RetryMiddleware.php

120 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Depicter\GuzzleHttp;
4
5 use Depicter\GuzzleHttp\Promise as P;
6 use Depicter\GuzzleHttp\Promise\PromiseInterface;
7 use Depicter\Psr\Http\Message\RequestInterface;
8 use Depicter\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 }
120