Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fdcf9ee

Browse files
committed
Retry on timeout
1 parent 0000dfe commit fdcf9ee

File tree

8 files changed

+29
-8
lines changed

8 files changed

+29
-8
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,7 @@ private function addHttpClientRetrySection()
16671667
->defaultValue([423, 425, 429, 500, 502, 503, 504, 507, 510])
16681668
->end()
16691669
->integerNode('max_retries')->defaultValue(3)->min(0)->end()
1670+
->floatNode('retry_timeout')->defaultNull()->min(0)->info('The idle timeout in seconds before retrying the request, defaults to the "default_socket_timeout" ini parameter.')->end()
16701671
->integerNode('delay')->defaultValue(1000)->min(0)->info('Time in ms to delay (or the initial value when multiplier is used)')->end()
16711672
->floatNode('multiplier')->defaultValue(2)->min(1)->info('If greater than 1, delay will grow exponentially for each retry: (delay * (multiple ^ retries))')->end()
16721673
->integerNode('max_delay')->defaultValue(0)->min(0)->info('Max time in ms that a retry should ever be delayed (0 = infinite)')->end()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2096,7 +2096,7 @@ private function registerHttpClientRetry(array $retryOptions, string $name, Cont
20962096
$container
20972097
->register($name.'.retry', RetryableHttpClient::class)
20982098
->setDecoratedService($name, null, -10) // lower priority than TraceableHttpClient
2099-
->setArguments([new Reference($name.'.retry.inner'), $deciderReference, $backoffReference, $retryOptions['max_retries'], new Reference('logger')])
2099+
->setArguments([new Reference($name.'.retry.inner'), $deciderReference, $backoffReference, $retryOptions['max_retries'], $retryOptions['retry_timeout'], new Reference('logger')])
21002100
->addTag('monolog.logger', ['channel' => 'http_client']);
21012101
}
21022102

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@
584584
<xsd:attribute name="backoff-service" type="xsd:string" />
585585
<xsd:attribute name="decider-service" type="xsd:string" />
586586
<xsd:attribute name="max-retries" type="xsd:integer" />
587+
<xsd:attribute name="retry-timeout" type="xsd:float" />
587588
<xsd:attribute name="delay" type="xsd:integer" />
588589
<xsd:attribute name="multiplier" type="xsd:float" />
589590
<xsd:attribute name="max-delay" type="xsd:float" />

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_retry.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
'decider_service' => null,
99
'http_codes' => [429, 500],
1010
'max_retries' => 2,
11+
'retry_timeout' => 10,
1112
'delay' => 100,
1213
'multiplier' => 2,
1314
'max_delay' => 0,

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_retry.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
delay="100"
1313
max-delay="0"
1414
max-retries="2"
15+
retry-timeout="10"
1516
multiplier="2"
1617
jitter="0.3">
1718
<framework:http-code>429</framework:http-code>

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_retry.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ framework:
66
decider_service: null
77
http_codes: [429, 500]
88
max_retries: 2
9+
retry_timeout: 10
910
delay: 100
1011
multiplier: 2
1112
max_delay: 0

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,7 @@ public function testHttpClientRetry()
15061506
$this->assertSame(0, $container->getDefinition('http_client.retry.exponential_backoff')->getArgument(2));
15071507
$this->assertSame(0.3, $container->getDefinition('http_client.retry.exponential_backoff')->getArgument(3));
15081508
$this->assertSame(2, $container->getDefinition('http_client.retry')->getArgument(3));
1509+
$this->assertSame(10, $container->getDefinition('http_client.retry')->getArgument(4));
15091510

15101511
$this->assertSame(RetryableHttpClient::class, $container->getDefinition('foo.retry')->getClass());
15111512
$this->assertSame(4, $container->getDefinition('foo.retry.exponential_backoff')->getArgument(1));

src/Symfony/Component/HttpClient/RetryableHttpClient.php

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,21 @@ class RetryableHttpClient implements HttpClientInterface
3636
private $decider;
3737
private $strategy;
3838
private $maxRetries;
39+
private $retryTimeout;
3940
private $logger;
4041

4142
/**
42-
* @param int $maxRetries The maximum number of times to retry
43+
* @param int $maxRetries The maximum number of times to retry
44+
* @param int $retryTimeout The idle timeout in seconds before retrying the request, defaults to the "default_socket_timeout" ini parameter.
4345
*/
44-
public function __construct(HttpClientInterface $client, RetryDeciderInterface $decider = null, RetryBackOffInterface $strategy = null, int $maxRetries = 3, LoggerInterface $logger = null)
46+
public function __construct(HttpClientInterface $client, RetryDeciderInterface $decider = null, RetryBackOffInterface $strategy = null, int $maxRetries = 3, float $retryTimeout = null, LoggerInterface $logger = null)
4547
{
4648
$this->client = $client;
4749
$this->decider = $decider ?? new HttpStatusCodeDecider();
4850
$this->strategy = $strategy ?? new ExponentialBackOff();
4951
$this->maxRetries = $maxRetries;
5052
$this->logger = $logger ?: new NullLogger();
53+
$this->retryTimeout = $retryTimeout ?? (float) ini_get('default_socket_timeout');
5154
}
5255

5356
public function request(string $method, string $url, array $options = []): ResponseInterface
@@ -59,11 +62,18 @@ public function request(string $method, string $url, array $options = []): Respo
5962
$retryCount = 0;
6063
$content = '';
6164
$firstChunk = null;
65+
$lastEventTime = \microtime(true);
6266

63-
return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options, &$retryCount, &$content, &$firstChunk) {
67+
return new AsyncResponse($this->client, $method, $url, $options + ['timeout' => $this->retryTimeout], function (ChunkInterface $chunk, AsyncContext $context) use (&$lastEventTime, $method, $url, $options, &$retryCount, &$content, &$firstChunk) {
6468
$exception = null;
6569
try {
66-
if ($chunk->isTimeout() || null !== $chunk->getInformationalStatus()) {
70+
if ($chunk->isTimeout() && \microtime(true) - $lastEventTime <= $this->retryTimeout) {
71+
yield $chunk;
72+
73+
return;
74+
}
75+
$lastEventTime = \microtime(true);
76+
if (null !== $chunk->getInformationalStatus()) {
6777
yield $chunk;
6878

6979
return;
@@ -124,11 +134,16 @@ public function request(string $method, string $url, array $options = []): Respo
124134
'delay' => $delay,
125135
]);
126136

127-
$context->replaceRequest($method, $url, $options);
128-
$context->pause($delay / 1000);
129-
137+
// it's expected to no having chunk in the next $delay seconds
138+
$lastEventTime = \microtime(true) + $delay / 1000;
130139
if ($retryCount >= $this->maxRetries) {
140+
$context->replaceRequest($method, $url, $options);
141+
$context->pause($delay / 1000);
142+
131143
$context->passthru();
144+
} else {
145+
$context->replaceRequest($method, $url, $options + ['timeout' => $this->retryTimeout + $delay / 1000]);
146+
$context->pause($delay / 1000);
132147
}
133148
});
134149
}

0 commit comments

Comments
 (0)