15
15
use Psr \Log \NullLogger ;
16
16
use Symfony \Component \HttpClient \Response \AsyncContext ;
17
17
use Symfony \Component \HttpClient \Response \AsyncResponse ;
18
- use Symfony \Component \HttpClient \Retry \ExponentialBackOff ;
19
- use Symfony \Component \HttpClient \Retry \HttpStatusCodeDecider ;
20
- use Symfony \Component \HttpClient \Retry \RetryBackOffInterface ;
21
- use Symfony \Component \HttpClient \Retry \RetryDeciderInterface ;
18
+ use Symfony \Component \HttpClient \Retry \GenericRetryStrategy ;
19
+ use Symfony \Component \HttpClient \Retry \RetryStrategyInterface ;
22
20
use Symfony \Contracts \HttpClient \ChunkInterface ;
23
21
use Symfony \Contracts \HttpClient \Exception \TransportExceptionInterface ;
24
22
use Symfony \Contracts \HttpClient \HttpClientInterface ;
@@ -33,19 +31,17 @@ class RetryableHttpClient implements HttpClientInterface
33
31
{
34
32
use AsyncDecoratorTrait;
35
33
36
- private $ decider ;
37
34
private $ strategy ;
38
35
private $ maxRetries ;
39
36
private $ logger ;
40
37
41
38
/**
42
39
* @param int $maxRetries The maximum number of times to retry
43
40
*/
44
- public function __construct (HttpClientInterface $ client , RetryDeciderInterface $ decider = null , RetryBackOffInterface $ strategy = null , int $ maxRetries = 3 , LoggerInterface $ logger = null )
41
+ public function __construct (HttpClientInterface $ client , RetryStrategyInterface $ strategy = null , int $ maxRetries = 3 , LoggerInterface $ logger = null )
45
42
{
46
43
$ this ->client = $ client ;
47
- $ this ->decider = $ decider ?? new HttpStatusCodeDecider ();
48
- $ this ->strategy = $ strategy ?? new ExponentialBackOff ();
44
+ $ this ->strategy = $ strategy ?? new GenericRetryStrategy ();
49
45
$ this ->maxRetries = $ maxRetries ;
50
46
$ this ->logger = $ logger ?: new NullLogger ();
51
47
}
@@ -69,23 +65,22 @@ public function request(string $method, string $url, array $options = []): Respo
69
65
return ;
70
66
}
71
67
} catch (TransportExceptionInterface $ exception ) {
72
- // catch TransportExceptionInterface to send it to strategy.
68
+ // catch TransportExceptionInterface to send it to the strategy
69
+ $ context ->setInfo ('retry_count ' , $ retryCount );
73
70
}
74
71
75
- $ statusCode = $ context ->getStatusCode ();
76
- $ headers = $ context ->getHeaders ();
77
72
if (null === $ exception ) {
78
73
if ($ chunk ->isFirst ()) {
79
- $ shouldRetry = $ this -> decider -> shouldRetry ( $ method , $ url , $ options , $ statusCode , $ headers , null );
74
+ $ context -> setInfo ( ' retry_count ' , $ retryCount );
80
75
81
- if (false === $ shouldRetry ) {
76
+ if (false === $ shouldRetry = $ this -> strategy -> shouldRetry ( $ context , null , null ) ) {
82
77
$ context ->passthru ();
83
78
yield $ chunk ;
84
79
85
80
return ;
86
81
}
87
82
88
- // Decider need body to decide
83
+ // Body is needed to decide
89
84
if (null === $ shouldRetry ) {
90
85
$ firstChunk = $ chunk ;
91
86
$ content = '' ;
@@ -94,12 +89,13 @@ public function request(string $method, string $url, array $options = []): Respo
94
89
}
95
90
} else {
96
91
$ content .= $ chunk ->getContent ();
92
+
97
93
if (!$ chunk ->isLast ()) {
98
94
return ;
99
95
}
100
- $ shouldRetry = $ this -> decider -> shouldRetry ( $ method , $ url , $ options , $ statusCode , $ headers , $ content );
101
- if (null === $ shouldRetry ) {
102
- throw new \LogicException (sprintf ('The "%s::shouldRetry" method must not return null when called with a body. ' , \get_class ($ this ->decider )));
96
+
97
+ if (null === $ shouldRetry = $ this -> strategy -> shouldRetry ( $ context , $ content , null ) ) {
98
+ throw new \LogicException (sprintf ('The "%s::shouldRetry() " method must not return null when called with a body. ' , \get_class ($ this ->strategy )));
103
99
}
104
100
105
101
if (false === $ shouldRetry ) {
@@ -113,14 +109,13 @@ public function request(string $method, string $url, array $options = []): Respo
113
109
}
114
110
}
115
111
116
- $ context ->setInfo ('retry_count ' , $ retryCount );
117
112
$ context ->getResponse ()->cancel ();
118
113
119
- $ delay = $ this ->getDelayFromHeader ($ headers ) ?? $ this ->strategy ->getDelay ($ retryCount , $ method , $ url , $ options , $ statusCode , $ headers , $ chunk instanceof LastChunk ? $ content : null , $ exception );
114
+ $ delay = $ this ->getDelayFromHeader ($ context -> getHeaders ()) ?? $ this ->strategy ->getDelay ($ context , $ chunk instanceof LastChunk ? $ content : null , $ exception );
120
115
++$ retryCount ;
121
116
122
- $ this ->logger ->info ('Error returned by the server. Retrying #{retryCount} using {delay} ms delay: ' .($ exception ? $ exception ->getMessage () : 'StatusCode : ' .$ statusCode ), [
123
- 'retryCount ' => $ retryCount ,
117
+ $ this ->logger ->info ('Try #{count} after {delay}ms ' .($ exception ? ' : ' . $ exception ->getMessage () : ', status code : ' .$ context -> getStatusCode () ), [
118
+ 'count ' => $ retryCount ,
124
119
'delay ' => $ delay ,
125
120
]);
126
121
@@ -139,6 +134,7 @@ private function getDelayFromHeader(array $headers): ?int
139
134
if (is_numeric ($ after )) {
140
135
return (int ) $ after * 1000 ;
141
136
}
137
+
142
138
if (false !== $ time = strtotime ($ after )) {
143
139
return max (0 , $ time - time ()) * 1000 ;
144
140
}
0 commit comments