Skip to content

Commit 69dd200

Browse files
committed
refactor: refactor RetryMiddleware to use backoff option
1 parent 626f9af commit 69dd200

File tree

1 file changed

+54
-27
lines changed

1 file changed

+54
-27
lines changed

src/Downloader/Middleware/RetryMiddleware.php

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace RoachPHP\Downloader\Middleware;
1515

16+
use InvalidArgumentException;
1617
use Psr\Log\LoggerInterface;
1718
use RoachPHP\Http\Response;
1819
use RoachPHP\Scheduling\RequestSchedulerInterface;
@@ -31,54 +32,80 @@ public function __construct(
3132
public function handleResponse(Response $response): Response
3233
{
3334
$request = $response->getRequest();
34-
35+
3536
/** @var int $retryCount */
3637
$retryCount = $request->getMeta('retry_count', 0);
3738

3839
/** @var list<int> $retryOnStatus */
3940
$retryOnStatus = $this->option('retryOnStatus');
40-
41+
4142
/** @var int $maxRetries */
4243
$maxRetries = $this->option('maxRetries');
4344

44-
if (\in_array($response->getStatus(), $retryOnStatus, true) && $retryCount < $maxRetries) {
45-
/** @var int $initialDelay */
46-
$initialDelay = $this->option('initialDelay');
47-
48-
/** @var float $delayMultiplier */
49-
$delayMultiplier = $this->option('delayMultiplier');
50-
51-
$delay = (int) ($initialDelay * ($delayMultiplier ** $retryCount));
52-
53-
$this->logger->info(
54-
'Retrying request',
55-
[
56-
'uri' => $request->getUri(),
57-
'status' => $response->getStatus(),
58-
'retry_count' => $retryCount + 1,
59-
'delay_ms' => $delay,
60-
],
45+
if (!\in_array($response->getStatus(), $retryOnStatus, true) || $retryCount >= $maxRetries) {
46+
return $response;
47+
}
48+
49+
$delay = $this->getDelay($retryCount);
50+
51+
$this->logger->info(
52+
'Retrying request',
53+
[
54+
'uri' => $request->getUri(),
55+
'status' => $response->getStatus(),
56+
'retry_count' => $retryCount + 1,
57+
'delay_ms' => $delay,
58+
],
59+
);
60+
61+
$retryRequest = $request
62+
->withMeta('retry_count', $retryCount + 1)
63+
->addOption('delay', $delay);
64+
65+
$this->scheduler->schedule($retryRequest);
66+
67+
return $response->drop('Request being retried');
68+
}
69+
70+
private function getDelay(int $retryCount): int
71+
{
72+
/** @var int|list<int> $backoff */
73+
$backoff = $this->option('backoff');
74+
75+
if (\is_int($backoff)) {
76+
return $backoff * 1000;
77+
}
78+
79+
if (!\is_array($backoff)) {
80+
throw new InvalidArgumentException(
81+
'backoff must be an integer or array, ' . \gettype($backoff) . ' given.',
6182
);
83+
}
6284

63-
$retryRequest = $request
64-
->withMeta('retry_count', $retryCount + 1)
65-
->addOption('delay', $delay);
85+
if ([] === $backoff) {
86+
throw new InvalidArgumentException('backoff array cannot be empty.');
87+
}
6688

67-
$this->scheduler->schedule($retryRequest);
89+
$nonIntegerValues = \array_filter($backoff, static fn ($value) => !\is_int($value));
6890

69-
return $response->drop('Request being retried');
91+
if ([] !== $nonIntegerValues) {
92+
throw new InvalidArgumentException(
93+
'backoff array must contain only integers. Found: ' .
94+
\implode(', ', \array_map('gettype', $nonIntegerValues)),
95+
);
7096
}
7197

72-
return $response;
98+
$delay = $backoff[$retryCount] ?? $backoff[\array_key_last($backoff)];
99+
100+
return $delay * 1000;
73101
}
74102

75103
private static function defaultOptions(): array
76104
{
77105
return [
78106
'retryOnStatus' => [500, 502, 503, 504],
79107
'maxRetries' => 3,
80-
'initialDelay' => 1000,
81-
'delayMultiplier' => 2.0,
108+
'backoff' => [1, 5, 10],
82109
];
83110
}
84111
}

0 commit comments

Comments
 (0)