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

Appearance settings

Commit 33da4c8

Browse filesBrowse files
feature #49809 [HttpClient] Allow using multiple base_uri as array for retries (Tiriel)
This PR was squashed before being merged into the 6.3 branch. Discussion ---------- [HttpClient] Allow using multiple base_uri as array for retries | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #43327 | License | MIT | Doc PR | TBD Allowing array of urls as `base_uri` option in `RetryableHttpClient` to allow retries on different base uris each time. Commits ------- b63ad40 [HttpClient] Allow using multiple base_uri as array for retries
2 parents 474239a + b63ad40 commit 33da4c8
Copy full SHA for 33da4c8

File tree

Expand file treeCollapse file tree

3 files changed

+135
-2
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+135
-2
lines changed

‎src/Symfony/Component/HttpClient/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpClient/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Add `UriTemplateHttpClient` to use URI templates as specified in the RFC 6570
88
* Add `ServerSentEvent::getArrayData()` to get the Server-Sent Event's data decoded as an array when it's a JSON payload
9+
* Allow array of urls as `base_uri` option value in `RetryableHttpClient` to retry on a new url each time
910

1011
6.2
1112
---

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpClient/RetryableHttpClient.php
+34-2Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class RetryableHttpClient implements HttpClientInterface, ResetInterface
3535
private RetryStrategyInterface $strategy;
3636
private int $maxRetries;
3737
private LoggerInterface $logger;
38+
private array $baseUris = [];
3839

3940
/**
4041
* @param int $maxRetries The maximum number of times to retry
@@ -47,13 +48,34 @@ public function __construct(HttpClientInterface $client, RetryStrategyInterface
4748
$this->logger = $logger ?? new NullLogger();
4849
}
4950

51+
public function withOptions(array $options): static
52+
{
53+
if (\array_key_exists('base_uri', $options)) {
54+
if (\is_array($options['base_uri'])) {
55+
$this->baseUris = $options['base_uri'];
56+
unset($options['base_uri']);
57+
} else {
58+
$this->baseUris = [];
59+
}
60+
}
61+
62+
$clone = clone $this;
63+
$clone->client = $this->client->withOptions($options);
64+
65+
return $clone;
66+
}
67+
5068
public function request(string $method, string $url, array $options = []): ResponseInterface
5169
{
70+
$baseUris = \array_key_exists('base_uri', $options) ? $options['base_uri'] : $this->baseUris;
71+
$baseUris = \is_array($baseUris) ? $baseUris : [];
72+
$options = self::shiftBaseUri($options, $baseUris);
73+
5274
if ($this->maxRetries <= 0) {
5375
return new AsyncResponse($this->client, $method, $url, $options);
5476
}
5577

56-
return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options) {
78+
return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options, &$baseUris) {
5779
static $retryCount = 0;
5880
static $content = '';
5981
static $firstChunk;
@@ -127,7 +149,7 @@ public function request(string $method, string $url, array $options = []): Respo
127149
]);
128150

129151
$context->setInfo('retry_count', $retryCount);
130-
$context->replaceRequest($method, $url, $options);
152+
$context->replaceRequest($method, $url, self::shiftBaseUri($options, $baseUris));
131153
$context->pause($delay / 1000);
132154

133155
if ($retryCount >= $this->maxRetries) {
@@ -168,4 +190,14 @@ private function passthru(AsyncContext $context, ?ChunkInterface $firstChunk, st
168190

169191
yield $lastChunk;
170192
}
193+
194+
private static function shiftBaseUri(array $options, array &$baseUris): array
195+
{
196+
if ($baseUris) {
197+
$baseUri = 1 < \count($baseUris) ? array_shift($baseUris) : current($baseUris);
198+
$options['base_uri'] = \is_array($baseUri) ? $baseUri[array_rand($baseUri)] : $baseUri;
199+
}
200+
201+
return $options;
202+
}
171203
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
+100Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,104 @@ public function testRetryOnErrorAssertContent()
244244
self::assertSame('Test out content', $response->getContent());
245245
self::assertSame('Test out content', $response->getContent(), 'Content should be buffered');
246246
}
247+
248+
public function testRetryWithMultipleBaseUris()
249+
{
250+
$client = new RetryableHttpClient(
251+
new MockHttpClient([
252+
new MockResponse('', ['http_code' => 500]),
253+
new MockResponse('Hit on second uri', ['http_code' => 200]),
254+
]),
255+
new GenericRetryStrategy([500], 0),
256+
1
257+
);
258+
259+
$response = $client->request('GET', 'foo-bar', [
260+
'base_uri' => [
261+
'http://example.com/a/',
262+
'http://example.com/b/',
263+
],
264+
]);
265+
266+
self::assertSame(200, $response->getStatusCode());
267+
self::assertSame('http://example.com/b/foo-bar', $response->getInfo('url'));
268+
}
269+
270+
public function testMultipleBaseUrisAsOptions()
271+
{
272+
$client = new RetryableHttpClient(
273+
new MockHttpClient([
274+
new MockResponse('', ['http_code' => 500]),
275+
new MockResponse('Hit on second uri', ['http_code' => 200]),
276+
]),
277+
new GenericRetryStrategy([500], 0),
278+
1
279+
);
280+
281+
$client = $client->withOptions([
282+
'base_uri' => [
283+
'http://example.com/a/',
284+
'http://example.com/b/',
285+
],
286+
]);
287+
288+
$response = $client->request('GET', 'foo-bar');
289+
290+
self::assertSame(200, $response->getStatusCode());
291+
self::assertSame('http://example.com/b/foo-bar', $response->getInfo('url'));
292+
}
293+
294+
public function testRetryWithMultipleBaseUrisShufflesNestedArray()
295+
{
296+
$client = new RetryableHttpClient(
297+
new MockHttpClient([
298+
new MockResponse('', ['http_code' => 500]),
299+
new MockResponse('Hit on second uri', ['http_code' => 200]),
300+
]),
301+
new GenericRetryStrategy([500], 0),
302+
1
303+
);
304+
305+
$response = $client->request('GET', 'foo-bar', [
306+
'base_uri' => [
307+
'http://example.com/a/',
308+
[
309+
'http://example.com/b/',
310+
'http://example.com/c/',
311+
],
312+
'http://example.com/d/',
313+
],
314+
]);
315+
316+
self::assertSame(200, $response->getStatusCode());
317+
self::assertMatchesRegularExpression('#^http://example.com/(b|c)/foo-bar$#', $response->getInfo('url'));
318+
}
319+
320+
public function testRetryWithMultipleBaseUrisPreservesNonNestedOrder()
321+
{
322+
$client = new RetryableHttpClient(
323+
new MockHttpClient([
324+
new MockResponse('', ['http_code' => 500]),
325+
new MockResponse('', ['http_code' => 500]),
326+
new MockResponse('', ['http_code' => 500]),
327+
new MockResponse('Hit on second uri', ['http_code' => 200]),
328+
]),
329+
new GenericRetryStrategy([500], 0),
330+
3
331+
);
332+
333+
$response = $client->request('GET', 'foo-bar', [
334+
'base_uri' => [
335+
'http://example.com/a/',
336+
[
337+
'http://example.com/b/',
338+
'http://example.com/c/',
339+
],
340+
'http://example.com/d/',
341+
],
342+
]);
343+
344+
self::assertSame(200, $response->getStatusCode());
345+
self::assertSame('http://example.com/d/foo-bar', $response->getInfo('url'));
346+
}
247347
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.