Skip to content

Commit

Permalink
feature #50240 [HttpClient] Add max_retries option to `RetryableHtt…
Browse files Browse the repository at this point in the history
…pClient` (danielburger1337)

This PR was squashed before being merged into the 6.4 branch.

Discussion
----------

[HttpClient] Add `max_retries` option to `RetryableHttpClient`

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | N/A
| License       | MIT
| Doc PR        | symfony/symfony-docs#18288

Added a `max_retries` option to RetryableHttpClient that allows the user to configure the RetryableHttpClient on a per request level, which is especially useful when `retry_failed` was configured for the global `http_client` service.

```php
<?php

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\RetryableHttpClient;

$client = HttpClient::create();
$client = new RetryableHttpClient($client, null, 3);

$client->request('GET', '/foo-bar', [
    'max_retries' => 1 // 0 disables retrying
]);

// $client = $client->withOptions(['max_retries' => 1]);
```

Commits
-------

496ba59 [HttpClient] Add `max_retries` option to `RetryableHttpClient`
  • Loading branch information
nicolas-grekas committed Jun 9, 2023
2 parents 124891a + 496ba59 commit 52a9292
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/Symfony/Component/HttpClient/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.4
---

* Add `max_retries` option to `RetryableHttpClient` to adjust the retry logic on a per request level

6.3
---

Expand Down
12 changes: 9 additions & 3 deletions src/Symfony/Component/HttpClient/RetryableHttpClient.php
Expand Up @@ -60,6 +60,9 @@ public function withOptions(array $options): static
}

$clone = clone $this;
$clone->maxRetries = (int) ($options['max_retries'] ?? $this->maxRetries);
unset($options['max_retries']);

$clone->client = $this->client->withOptions($options);

return $clone;
Expand All @@ -71,11 +74,14 @@ public function request(string $method, string $url, array $options = []): Respo
$baseUris = \is_array($baseUris) ? $baseUris : [];
$options = self::shiftBaseUri($options, $baseUris);

if ($this->maxRetries <= 0) {
$maxRetries = (int) ($options['max_retries'] ?? $this->maxRetries);
unset($options['max_retries']);

if ($maxRetries <= 0) {
return new AsyncResponse($this->client, $method, $url, $options);
}

return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options, &$baseUris) {
return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options, $maxRetries, &$baseUris) {
static $retryCount = 0;
static $content = '';
static $firstChunk;
Expand Down Expand Up @@ -152,7 +158,7 @@ public function request(string $method, string $url, array $options = []): Respo
$context->replaceRequest($method, $url, self::shiftBaseUri($options, $baseUris));
$context->pause($delay / 1000);

if ($retryCount >= $this->maxRetries) {
if ($retryCount >= $maxRetries) {
$context->passthru();
}
});
Expand Down
41 changes: 41 additions & 0 deletions src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
Expand Up @@ -344,4 +344,45 @@ public function testRetryWithMultipleBaseUrisPreservesNonNestedOrder()
self::assertSame(200, $response->getStatusCode());
self::assertSame('http://example.com/d/foo-bar', $response->getInfo('url'));
}

public function testMaxRetriesOption()
{
$client = new RetryableHttpClient(
new MockHttpClient([
new MockResponse('', ['http_code' => 500]),
new MockResponse('', ['http_code' => 502]),
new MockResponse('', ['http_code' => 200]),
]),
new GenericRetryStrategy([500, 502], 0),
3
);

$response = $client->request('GET', 'http://example.com/foo-bar', [
'max_retries' => 1,
]);

self::assertSame(502, $response->getStatusCode());
}

public function testMaxRetriesWithOptions()
{
$client = new RetryableHttpClient(
new MockHttpClient([
new MockResponse('', ['http_code' => 500]),
new MockResponse('', ['http_code' => 502]),
new MockResponse('', ['http_code' => 504]),
new MockResponse('', ['http_code' => 200]),
]),
new GenericRetryStrategy([500, 502, 504], 0),
3
);

$client = $client->withOptions([
'max_retries' => 2,
]);

$response = $client->request('GET', 'http://example.com/foo-bar');

self::assertSame(504, $response->getStatusCode());
}
}

0 comments on commit 52a9292

Please sign in to comment.