Skip to content

Commit b681cbd

Browse files
authored
Create RetryMiddleware.php
1 parent 725955e commit b681cbd

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2024 Kai Sassnowski
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*
11+
* @see https://github.com/roach-php/roach
12+
*/
13+
14+
namespace RoachPHP\Downloader\Middleware;
15+
16+
use Psr\Log\LoggerInterface;
17+
use RoachPHP\Http\Response;
18+
use RoachPHP\Scheduling\RequestSchedulerInterface;
19+
use RoachPHP\Support\Configurable;
20+
21+
final class RetryMiddleware implements ResponseMiddlewareInterface
22+
{
23+
use Configurable;
24+
25+
public function __construct(
26+
private readonly RequestSchedulerInterface $scheduler,
27+
private readonly LoggerInterface $logger,
28+
) {
29+
}
30+
31+
public function handleResponse(Response $response): Response
32+
{
33+
$request = $response->getRequest();
34+
35+
/** @var int $retryCount */
36+
$retryCount = $request->getMeta('retry_count', 0);
37+
38+
/** @var list<int> $retryOnStatus */
39+
$retryOnStatus = $this->option('retryOnStatus');
40+
41+
/** @var int $maxRetries */
42+
$maxRetries = $this->option('maxRetries');
43+
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+
],
61+
);
62+
63+
$retryRequest = $request
64+
->withMeta('retry_count', $retryCount + 1)
65+
->addOption('delay', $delay);
66+
67+
$this->scheduler->schedule($retryRequest);
68+
69+
return $response->drop('Request being retried');
70+
}
71+
72+
return $response;
73+
}
74+
75+
private static function defaultOptions(): array
76+
{
77+
return [
78+
'retryOnStatus' => [500, 502, 503, 504],
79+
'maxRetries' => 3,
80+
'initialDelay' => 1000,
81+
'delayMultiplier' => 2.0,
82+
];
83+
}
84+
}

0 commit comments

Comments
 (0)