17
17
/**
18
18
* A retry backOff with a constant or exponential retry delay.
19
19
*
20
- * For example, if $delayMilliseconds=10000 & $multiplier=1 (default) ,
20
+ * For example, if $delayMilliseconds=10000 & $multiplier=1,
21
21
* each retry will wait exactly 10 seconds.
22
22
*
23
23
* But if $delayMilliseconds=10000 & $multiplier=2:
@@ -33,13 +33,15 @@ final class ExponentialBackOff implements RetryBackOffInterface
33
33
private $ delayMilliseconds ;
34
34
private $ multiplier ;
35
35
private $ maxDelayMilliseconds ;
36
+ private $ jitter ;
36
37
37
38
/**
38
39
* @param int $delayMilliseconds Amount of time to delay (or the initial value when multiplier is used)
39
40
* @param float $multiplier Multiplier to apply to the delay each time a retry occurs
40
41
* @param int $maxDelayMilliseconds Maximum delay to allow (0 means no maximum)
42
+ * @param float $jitter Probability of randomness int delay (0 = none, 1 = 100% random)
41
43
*/
42
- public function __construct (int $ delayMilliseconds = 1000 , float $ multiplier = 2.0 , int $ maxDelayMilliseconds = 0 )
44
+ public function __construct (int $ delayMilliseconds = 1000 , float $ multiplier = 2.0 , int $ maxDelayMilliseconds = 0 , float $ jitter = 0.1 )
43
45
{
44
46
if ($ delayMilliseconds < 0 ) {
45
47
throw new InvalidArgumentException (sprintf ('Delay must be greater than or equal to zero: "%s" given. ' , $ delayMilliseconds ));
@@ -55,11 +57,20 @@ public function __construct(int $delayMilliseconds = 1000, float $multiplier = 2
55
57
throw new InvalidArgumentException (sprintf ('Max delay must be greater than or equal to zero: "%s" given. ' , $ maxDelayMilliseconds ));
56
58
}
57
59
$ this ->maxDelayMilliseconds = $ maxDelayMilliseconds ;
60
+
61
+ if ($ jitter < 0 || $ jitter > 1 ) {
62
+ throw new InvalidArgumentException (sprintf ('Jitter must be between 0 and 1: "%s" given. ' , $ jitter ));
63
+ }
64
+ $ this ->jitter = $ jitter ;
58
65
}
59
66
60
67
public function getDelay (int $ retryCount , string $ requestMethod , string $ requestUrl , array $ requestOptions , int $ responseStatusCode , array $ responseHeaders , ?string $ responseContent , ?TransportExceptionInterface $ exception ): int
61
68
{
62
69
$ delay = $ this ->delayMilliseconds * $ this ->multiplier ** $ retryCount ;
70
+ if ($ this ->jitter > 0 ) {
71
+ $ randomness = $ delay * $ this ->jitter ;
72
+ $ delay = $ delay + random_int (-$ randomness , +$ randomness );
73
+ }
63
74
64
75
if ($ delay > $ this ->maxDelayMilliseconds && 0 !== $ this ->maxDelayMilliseconds ) {
65
76
return $ this ->maxDelayMilliseconds ;
0 commit comments