Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2d35c26

Browse files
committed
Parameterize list of retryed Http methods
1 parentca220a1 commit2d35c26

File tree

8 files changed

+132
-51
lines changed

8 files changed

+132
-51
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php‎

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
useSymfony\Component\DependencyInjection\Exception\LogicException;
2525
useSymfony\Component\Form\Form;
2626
useSymfony\Component\HttpClient\HttpClient;
27+
useSymfony\Component\HttpClient\Retry\HttpStatusCodeDecider;
2728
useSymfony\Component\HttpFoundation\Cookie;
2829
useSymfony\Component\Lock\Lock;
2930
useSymfony\Component\Lock\Store\SemaphoreStore;
@@ -1644,8 +1645,8 @@ private function addHttpClientRetrySection()
16441645
if (isset($v['backoff_service']) && (isset($v['delay']) ||isset($v['multiplier']) ||isset($v['max_delay']))) {
16451646
thrownew \InvalidArgumentException('The "backoff_service" option cannot be used along with the "delay", "multiplier" or "max_delay" options.');
16461647
}
1647-
if (isset($v['decider_service']) && (isset($v['http_codes']))) {
1648-
thrownew \InvalidArgumentException('The "decider_service" option cannot be used along with the "http_codes" options.');
1648+
if (isset($v['decider_service']) && (isset($v['http_codes']) ||isset($v['idempotent_http_codes']))) {
1649+
thrownew \InvalidArgumentException('The "decider_service" option cannot be used along with the "http_codes"or "idempotent_http_codes"options.');
16491650
}
16501651

16511652
return$v;
@@ -1663,8 +1664,32 @@ private function addHttpClientRetrySection()
16631664
})
16641665
->end()
16651666
->prototype('integer')->end()
1666-
->info('A list of HTTP status code that triggers a retry')
1667-
->defaultValue([423,425,429,500,502,503,504,507,510])
1667+
->info('A list of HTTP status code that triggers a retry regardless the method')
1668+
->defaultValue([423,425,429,502,503,507])
1669+
->end()
1670+
->arrayNode('idempotent_http_codes')
1671+
->performNoDeepMerging()
1672+
->beforeNormalization()
1673+
->ifArray()
1674+
->then(function ($v) {
1675+
returnarray_filter(array_values($v));
1676+
})
1677+
->end()
1678+
->prototype('integer')->end()
1679+
->info('A list of HTTP status code that triggers a retry on idempotent methods')
1680+
->defaultValue([500,504,510])
1681+
->end()
1682+
->arrayNode('methods')
1683+
->performNoDeepMerging()
1684+
->beforeNormalization()
1685+
->ifArray()
1686+
->then(function ($v) {
1687+
returnarray_filter(array_values($v));
1688+
})
1689+
->end()
1690+
->prototype('scalar')->end()
1691+
->info('A list of HTTP request method code that are taken into account')
1692+
->defaultValue(['*'])
16681693
->end()
16691694
->integerNode('max_retries')->defaultValue(3)->min(0)->end()
16701695
->integerNode('delay')->defaultValue(1000)->min(0)->info('Time in ms to delay (or the initial value when multiplier is used)')->end()

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2086,7 +2086,8 @@ private function registerHttpClientRetry(array $retryOptions, string $name, Cont
20862086
$retryServiceId =$name.'.retry.decider';
20872087
$retryDefinition =newChildDefinition('http_client.retry.abstract_httpstatuscode_decider');
20882088
$retryDefinition
2089-
->replaceArgument(0,$retryOptions['http_codes']);
2089+
->replaceArgument(0,$retryOptions['http_codes'])
2090+
->replaceArgument(1,$retryOptions['idempotent_http_codes']);
20902091
$container->setDefinition($retryServiceId,$retryDefinition);
20912092

20922093
$deciderReference =newReference($retryServiceId);

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
->abstract()
6464
->args([
6565
abstract_arg('http codes'),
66+
abstract_arg('idempotent http codes'),
6667
])
6768
;
6869
};

‎src/Symfony/Component/HttpClient/Retry/HttpStatusCodeDecider.php‎

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,38 @@
1111

1212
namespaceSymfony\Component\HttpClient\Retry;
1313

14+
useSymfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
15+
1416
/**
1517
* Decides to retry the request when HTTP status codes belong to the given list of codes.
1618
*
1719
* @author Jérémy Derussé <jeremy@derusse.com>
1820
*/
1921
finalclass HttpStatusCodeDeciderimplements RetryDeciderInterface
2022
{
23+
publicconstDEFAULT_STATUS_CODES = [423,425,429,502,503,507];
24+
publicconstDEFAULT_IDEMPOTENT_STATUS_CODES = [500,504,510];
25+
publicconstIDEMPOTENT_METHODS = ['GET','HEAD','PUT','DELETE','OPTIONS','TRACE'];
26+
2127
private$statusCodes;
28+
private$idempotentStatusCodes;
2229

2330
/**
24-
* @param array $statusCodes List of HTTP status codes that trigger a retry
31+
* @param array $statusCodes List of HTTP status codes that trigger a retry regardless the method
32+
* @param array $idempotentStatusCodes List of HTTP status codes that trigger a retry on idempotent methods
2533
*/
26-
publicfunction__construct(array$statusCodes =[423,425,429,500,502,503,504,507,510])
34+
publicfunction__construct(array$statusCodes =self::DEFAULT_STATUS_CODES,array$idempotentStatusCodes =self::DEFAULT_IDEMPOTENT_STATUS_CODES)
2735
{
28-
$this->statusCodes =$statusCodes;
36+
$this->statusCodes =array_fill_keys($statusCodes,true);
37+
$this->idempotentStatusCodes =array_fill_keys($idempotentStatusCodes,true);
2938
}
3039

31-
publicfunctionshouldRetry(string$requestMethod,string$requestUrl,array$requestOptions,int$responseStatusCode,array$responseHeaders, ?string$responseContent): ?bool
40+
publicfunctionshouldRetry(int$retryCount,string$requestMethod,string$requestUrl,array$requestOptions,int$responseStatusCode,array$responseHeaders, ?string$responseContent, ?TransportExceptionInterface$exception): ?bool
3241
{
33-
return\in_array($responseStatusCode,$this->statusCodes,true);
42+
if (isset($this->statusCodes[$responseStatusCode])) {
43+
returntrue;
44+
}
45+
46+
return\in_array(strtoupper($requestMethod),self::IDEMPOTENT_METHODS,true) && (null !==$exception ||isset($this->idempotentStatusCodes[$responseStatusCode]));
3447
}
3548
}

‎src/Symfony/Component/HttpClient/Retry/RetryDeciderInterface.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespaceSymfony\Component\HttpClient\Retry;
1313

14+
useSymfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
15+
1416
/**
1517
* @author Jérémy Derussé <jeremy@derusse.com>
1618
*/
@@ -23,5 +25,5 @@ interface RetryDeciderInterface
2325
*
2426
* @return ?bool Returns null to signal that the body is required to take a decision
2527
*/
26-
publicfunctionshouldRetry(string$requestMethod,string$requestUrl,array$requestOptions,int$responseStatusCode,array$responseHeaders, ?string$responseContent): ?bool;
28+
publicfunctionshouldRetry(int$retryCount,string$requestMethod,string$requestUrl,array$requestOptions,int$responseStatusCode,array$responseHeaders, ?string$responseContent, ?TransportExceptionInterface$exception): ?bool;
2729
}

‎src/Symfony/Component/HttpClient/RetryableHttpClient.php‎

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -74,42 +74,59 @@ public function request(string $method, string $url, array $options = []): Respo
7474

7575
$statusCode =$context->getStatusCode();
7676
$headers =$context->getHeaders();
77-
if (null ===$exception) {
78-
if ($chunk->isFirst()) {
79-
$shouldRetry =$this->decider->shouldRetry($method,$url,$options,$statusCode,$headers,null);
77+
if (null !==$exception) {
78+
$shouldRetry =$this->decider->shouldRetry($retryCount,$method,$url,$options,$statusCode,$headers,null,$exception);
79+
if (null ===$shouldRetry) {
80+
thrownew \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with an exception.',\get_class($this->decider)));
81+
}
8082

81-
if (false ===$shouldRetry) {
82-
$context->passthru();
83+
if (false ===$shouldRetry) {
84+
$context->passthru();
85+
if (null !==$firstChunk) {
86+
yield$firstChunk;
87+
yield$context->createChunk($content);
88+
yield$chunk;
89+
}else {
8390
yield$chunk;
84-
85-
return;
8691
}
92+
$content ='';
8793

88-
// Decider need body to decide
89-
if (null ===$shouldRetry) {
90-
$firstChunk =$chunk;
91-
$content ='';
94+
return;
95+
}
96+
}elseif ($chunk->isFirst()) {
97+
$shouldRetry =$this->decider->shouldRetry($retryCount,$method,$url,$options,$statusCode,$headers,null,null);
9298

93-
return;
94-
}
95-
}else {
96-
$content .=$chunk->getContent();
97-
if (!$chunk->isLast()) {
98-
return;
99-
}
100-
$shouldRetry =$this->decider->shouldRetry($method,$url,$options,$statusCode,$headers,$content);
101-
if (null ===$shouldRetry) {
102-
thrownew \LogicException(sprintf('The "%s::shouldRetry" method must not return null when called with a body.',\get_class($this->decider)));
103-
}
99+
if (false ===$shouldRetry) {
100+
$context->passthru();
101+
yield$chunk;
104102

105-
if (false ===$shouldRetry) {
106-
$context->passthru();
107-
yield$firstChunk;
108-
yield$context->createChunk($content);
109-
$content ='';
103+
return;
104+
}
110105

111-
return;
112-
}
106+
// Decider need body to decide
107+
if (null ===$shouldRetry) {
108+
$firstChunk =$chunk;
109+
$content ='';
110+
111+
return;
112+
}
113+
}else {
114+
$content .=$chunk->getContent();
115+
if (!$chunk->isLast()) {
116+
return;
117+
}
118+
$shouldRetry =$this->decider->shouldRetry($retryCount,$method,$url,$options,$statusCode,$headers,$content,null);
119+
if (null ===$shouldRetry) {
120+
thrownew \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with a body.',\get_class($this->decider)));
121+
}
122+
123+
if (false ===$shouldRetry) {
124+
$context->passthru();
125+
yield$firstChunk;
126+
yield$context->createChunk($content);
127+
$content ='';
128+
129+
return;
113130
}
114131
}
115132

‎src/Symfony/Component/HttpClient/Tests/Retry/HttpStatusCodeDeciderTest.php‎

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,42 @@
1212
namespaceSymfony\Component\HttpClient\Tests\Retry;
1313

1414
usePHPUnit\Framework\TestCase;
15+
useSymfony\Component\HttpClient\Exception\TransportException;
1516
useSymfony\Component\HttpClient\Retry\HttpStatusCodeDecider;
17+
useSymfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
1618

1719
class HttpStatusCodeDeciderTestextends TestCase
1820
{
19-
publicfunctiontestShouldRetryStatusCode()
21+
/**
22+
* @dataProvider provideRetryable
23+
*/
24+
publicfunctiontestShouldRetry(string$method,int$code, ?TransportExceptionInterface$exception)
2025
{
21-
$decider =newHttpStatusCodeDecider([500]);
26+
$decider =newHttpStatusCodeDecider();
2227

23-
self::assertTrue($decider->shouldRetry('GET','http://example.com/', [],500, [],null));
28+
$this->assertTrue($decider->shouldRetry(1,$method,'http://example.com/', [],$code, [],null,$exception));
2429
}
2530

26-
publicfunctiontestIsNotRetryableOk()
31+
publicfunctionprovideRetryable():iterable
2732
{
28-
$decider =newHttpStatusCodeDecider([500]);
33+
yield ['GET',200,newTransportException()];
34+
yield ['GET',500,null];
35+
yield ['POST',429,null];
36+
}
37+
38+
/**
39+
* @dataProvider provideNotRetryable
40+
*/
41+
publicfunctiontestShouldNotRetry(string$method,int$code, ?TransportExceptionInterface$exception)
42+
{
43+
$decider =newHttpStatusCodeDecider();
2944

30-
self::assertFalse($decider->shouldRetry('GET','http://example.com/', [],200, [],null));
45+
$this->assertFalse($decider->shouldRetry(1,$method,'http://example.com/', [],$code, [],null,$exception));
46+
}
47+
48+
publicfunctionprovideNotRetryable():iterable
49+
{
50+
yield ['POST',200,newTransportException()];
51+
yield ['POST',500,null];
3152
}
3253
}

‎src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
useSymfony\Component\HttpClient\Retry\HttpStatusCodeDecider;
1111
useSymfony\Component\HttpClient\Retry\RetryDeciderInterface;
1212
useSymfony\Component\HttpClient\RetryableHttpClient;
13+
useSymfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
1314

1415
class RetryableHttpClientTestextends TestCase
1516
{
@@ -20,7 +21,7 @@ public function testRetryOnError()
2021
newMockResponse('', ['http_code' =>500]),
2122
newMockResponse('', ['http_code' =>200]),
2223
]),
23-
newHttpStatusCodeDecider([500]),
24+
newHttpStatusCodeDecider(['*'], [500]),
2425
newExponentialBackOff(0),
2526
1
2627
);
@@ -38,7 +39,7 @@ public function testRetryRespectStrategy()
3839
newMockResponse('', ['http_code' =>500]),
3940
newMockResponse('', ['http_code' =>200]),
4041
]),
41-
newHttpStatusCodeDecider([500]),
42+
newHttpStatusCodeDecider(['*'], [500]),
4243
newExponentialBackOff(0),
4344
1
4445
);
@@ -57,7 +58,7 @@ public function testRetryWithBody()
5758
newMockResponse('', ['http_code' =>200]),
5859
]),
5960
newclass()implements RetryDeciderInterface {
60-
publicfunctionshouldRetry(string$requestMethod,string$requestUrl,array$requestOptions,int$responseCode,array$responseHeaders, ?string$responseContent): ?bool
61+
publicfunctionshouldRetry(int$retryCount,string$requestMethod,string$requestUrl,array$requestOptions,int$responseCode,array$responseHeaders, ?string$responseContent, ?TransportExceptionInterface$exception): ?bool
6162
{
6263
returnnull ===$responseContent ?null :200 !==$responseCode;
6364
}
@@ -79,7 +80,7 @@ public function testRetryWithBodyInvalid()
7980
newMockResponse('', ['http_code' =>200]),
8081
]),
8182
newclass()implements RetryDeciderInterface {
82-
publicfunctionshouldRetry(string$requestMethod,string$requestUrl,array$requestOptions,int$responseCode,array$responseHeaders, ?string$responseContent,\Throwable$throwable =null): ?bool
83+
publicfunctionshouldRetry(int$retryCount,string$requestMethod,string$requestUrl,array$requestOptions,int$responseCode,array$responseHeaders, ?string$responseContent,TransportExceptionInterface$throwable =null): ?bool
8384
{
8485
returnnull;
8586
}
@@ -100,7 +101,7 @@ public function testStreamNoRetry()
100101
newMockHttpClient([
101102
newMockResponse('', ['http_code' =>500]),
102103
]),
103-
newHttpStatusCodeDecider([500]),
104+
newHttpStatusCodeDecider(['*'], [500]),
104105
newExponentialBackOff(0),
105106
0
106107
);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp