Completed
Push — master ( 100271...ba573b )
by Michael
02:54
created

src/RetryMiddleware.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
    {
91
        return function ($reason) use ($req, $options) {
92
            if (!call_user_func(
93
                $this->decider,
94
                $options['retries'],
95
                $req,
96
                null,
97
                $reason
98
            )) {
99
                return new RejectedPromise($reason);
100
            }
101
            return $this->doRetry($req, $options);
102
        };
103
    }
104
105
    private function doRetry(RequestInterface $request, array $options)
106
    {
107
        $options['delay'] = call_user_func($this->delay, ++$options['retries']);
108
109
        return $this($request, $options);
110
    }
111
}
112