Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
     */
1441 ariadna 43
    public function __construct(callable $decider, callable $nextHandler, ?callable $delay = null)
1 efrain 44
    {
45
        $this->decider = $decider;
46
        $this->nextHandler = $nextHandler;
1441 ariadna 47
        $this->delay = $delay ?: __CLASS__.'::exponentialDelay';
1 efrain 48
    }
49
 
50
    /**
51
     * Default exponential backoff delay function.
52
     *
53
     * @return int milliseconds.
54
     */
55
    public static function exponentialDelay(int $retries): int
56
    {
1441 ariadna 57
        return (int) 2 ** ($retries - 1) * 1000;
1 efrain 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;
1441 ariadna 67
 
1 efrain 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
            }
1441 ariadna 89
 
1 efrain 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
            }
1441 ariadna 108
 
1 efrain 109
            return $this->doRetry($req, $options);
110
        };
111
    }
112
 
1441 ariadna 113
    private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface
1 efrain 114
    {
115
        $options['delay'] = ($this->delay)(++$options['retries'], $response, $request);
116
 
117
        return $this($request, $options);
118
    }
119
}