Skip to content

Commit

Permalink
Merge pull request #6 from Innmind/retry-too-many-requests
Browse files Browse the repository at this point in the history
Apply retry when the response is a "too many requests"
  • Loading branch information
Baptouuuu authored Jul 17, 2024
2 parents 14d4b83 + 43a4cfb commit 3d67ae6
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased]

### Changed

- `429 Too Many Requests` errors are now retried when using `Innmind\HttpTransport\ExponentialBackoff`

## 7.2.1 - 2024-03-01

### Fixed
Expand Down
3 changes: 3 additions & 0 deletions src/ExponentialBackoff.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Innmind\HttpTransport;

use Innmind\Http\Request;
use Innmind\Http\Response\StatusCode;
use Innmind\TimeContinuum\{
Period,
Earth\Period\Millisecond,
Expand Down Expand Up @@ -74,6 +75,8 @@ private function maybeRetry(
Period $period,
): Either {
return $result->otherwise(fn($error) => match (true) {
$error instanceof ClientError &&
$error->response()->statusCode() === StatusCode::tooManyRequests => $this->retry($request, $period),
$error instanceof ServerError => $this->retry($request, $period),
$error instanceof ConnectionFailed => $this->retry($request, $period),
default => $this->return($error),
Expand Down
43 changes: 43 additions & 0 deletions tests/ExponentialBackoffTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,49 @@ public function testDoesntRetryWhenFailureOnFirstCall()
$this->assertEquals($expected, $fulfill($request));
}

public function testRetryWhileThereIsStillATooManyRequestsError()
{
$fulfill = ExponentialBackoff::of(
$inner = $this->createMock(Transport::class),
$halt = $this->createMock(Halt::class),
);
$request = Request::of(
Url::of('/'),
Method::get,
ProtocolVersion::v11,
);
$response = Response::of(
StatusCode::tooManyRequests,
$request->protocolVersion(),
);
$inner
->expects($this->exactly(12))
->method('__invoke')
->with($request)
->willReturn($expected = Either::left(new ClientError($request, $response)));
$halt
->expects($matcher = $this->exactly(10))
->method('__invoke')
->willReturnCallback(function($period) use ($matcher) {
match ($matcher->numberOfInvocations()) {
1 => $this->assertEquals(new Millisecond(100), $period),
2 => $this->assertEquals(new Millisecond(271), $period),
3 => $this->assertEquals(new Millisecond(738), $period),
4 => $this->assertEquals(new Millisecond(2008), $period),
5 => $this->assertEquals(new Millisecond(5459), $period),
6 => $this->assertEquals(new Millisecond(100), $period),
7 => $this->assertEquals(new Millisecond(271), $period),
8 => $this->assertEquals(new Millisecond(738), $period),
9 => $this->assertEquals(new Millisecond(2008), $period),
10 => $this->assertEquals(new Millisecond(5459), $period),
};
});

$this->assertEquals($expected, $fulfill($request));
// to make sure halt periods are kept between requests
$this->assertEquals($expected, $fulfill($request));
}

public function testRetryWhileThereIsStillAServerError()
{
$fulfill = ExponentialBackoff::of(
Expand Down

0 comments on commit 3d67ae6

Please sign in to comment.