From 67de3bb631900fda6ed600a1ddd0f6b0e2e3c4dc Mon Sep 17 00:00:00 2001 From: Samuel Gomis Date: Thu, 10 Aug 2023 17:53:50 +0200 Subject: [PATCH 1/4] feat(DX-160): implement retry for too many request --- src/Client/HttpClient.php | 19 ++++++++ src/Client/Options.php | 16 ++++++- tests/Api/AkeneoPimClientBuilderTest.php | 57 ++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/Api/AkeneoPimClientBuilderTest.php diff --git a/src/Client/HttpClient.php b/src/Client/HttpClient.php index feb23e14..07ca4746 100644 --- a/src/Client/HttpClient.php +++ b/src/Client/HttpClient.php @@ -2,6 +2,8 @@ namespace Akeneo\Pim\ApiClient\Client; +use Akeneo\Pim\ApiClient\Exception\TooManyRequestsHttpException; +use ECSPrefix202306\Symfony\Component\VarDumper\VarDumper; use GuzzleHttp\Promise\PromiseInterface; use Http\Promise\Promise; use Psr\Http\Message\RequestFactoryInterface; @@ -9,6 +11,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\StreamInterface; +use function ECSPrefix202306\dd; /** * Http client to send a request without any authentication. @@ -75,6 +78,8 @@ public function sendRequest(string $httpMethod, $uri, array $headers = [], $body $response = $this->httpClient->sendRequest($request); + $response = $this->retry($response, $request); + return $this->httpExceptionHandler->transformResponseToException($request, $response); } @@ -88,4 +93,18 @@ public function sendAsync( return $this->httpClient->sendAsyncRequest($request); } + + private function retry(ResponseInterface $response, RequestInterface $request, int $retryDelay = 2): ResponseInterface + { + if ($this->options->canRetry() && HttpClient::HTTP_TOO_MANY_REQUESTS === $response->getStatusCode()) { + $retry = 0; + while ($this->options->getMaxRetry() > $retry && HttpClient::HTTP_TOO_MANY_REQUESTS === $response->getStatusCode()) { + usleep($retryDelay * 1000); + $response = $this->httpClient->sendRequest($request); + $retry++; + var_dump($response->getStatusCode()); + } + } + return $response; + } } diff --git a/src/Client/Options.php b/src/Client/Options.php index ff53ca9f..cc1e38dc 100644 --- a/src/Client/Options.php +++ b/src/Client/Options.php @@ -9,7 +9,7 @@ class Options { private function __construct( - private array $options + private array $options, ) { } @@ -19,8 +19,12 @@ public static function fromArray(array $options): self $resolver->setDefaults([ 'headers' => [], + 'retry' => false, + 'max-retry' => 5, ]); $resolver->setAllowedTypes('headers', 'string[]'); + $resolver->setAllowedTypes('retry', 'bool'); + $resolver->setAllowedTypes('max-retry', 'int'); $options = $resolver->resolve($options); @@ -39,4 +43,14 @@ public function getHeaders(): array { return $this->options['headers']; } + + public function getMaxRetry(): int + { + return $this->options['max-retry']; + } + + public function canRetry(): bool + { + return $this->options['retry']; + } } diff --git a/tests/Api/AkeneoPimClientBuilderTest.php b/tests/Api/AkeneoPimClientBuilderTest.php new file mode 100644 index 00000000..38810789 --- /dev/null +++ b/tests/Api/AkeneoPimClientBuilderTest.php @@ -0,0 +1,57 @@ +server->setResponseOfPath( + '/' . ProductApi::PRODUCTS_URI, + new ResponseStack( + new Response('', [], 429), + new Response('', [], 429), + new Response('', [], 429), + new Response('', [], 429), + new Response('', [], 201), + ) + ); + + $api = $this->createClientByPassword()->getProductApi(); + $response = $api->create('new_shoes', []); + + + + for ($i = 0; $i < 5; $i++) { + $this->server->getRequestByOffset($i); + VarDumper::dump($this->server->getRequestByOffset(0)); + + Assert::assertSame(201, $response); + } + } + + protected function createClientByPassword(): AkeneoPimClientInterface + { + $clientBuilder = new AkeneoPimClientBuilder($this->server->getServerRoot(), [ + 'retry' => true, + 'max-retry' => 5, + ]); + + return $clientBuilder->buildAuthenticatedByPassword( + 'client_id', + 'secret', + 'username', + 'password' + ); + } +} From d5e92737d05df065ad476e31ba0c7332196b12d9 Mon Sep 17 00:00:00 2001 From: Samuel Gomis Date: Fri, 11 Aug 2023 11:00:23 +0200 Subject: [PATCH 2/4] feat(DX-160): fix --- src/Client/HttpClient.php | 1 - tests/Api/AkeneoPimClientBuilderTest.php | 12 ++---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Client/HttpClient.php b/src/Client/HttpClient.php index 07ca4746..1cc101a7 100644 --- a/src/Client/HttpClient.php +++ b/src/Client/HttpClient.php @@ -102,7 +102,6 @@ private function retry(ResponseInterface $response, RequestInterface $request, i usleep($retryDelay * 1000); $response = $this->httpClient->sendRequest($request); $retry++; - var_dump($response->getStatusCode()); } } return $response; diff --git a/tests/Api/AkeneoPimClientBuilderTest.php b/tests/Api/AkeneoPimClientBuilderTest.php index 38810789..12981b32 100644 --- a/tests/Api/AkeneoPimClientBuilderTest.php +++ b/tests/Api/AkeneoPimClientBuilderTest.php @@ -9,12 +9,11 @@ use Akeneo\Pim\ApiClient\Api\ProductApi; use donatj\MockWebServer\Response; use donatj\MockWebServer\ResponseStack; -use ECSPrefix202306\Symfony\Component\VarDumper\VarDumper; use PHPUnit\Framework\Assert; final class AkeneoPimClientBuilderTest extends ApiTestCase { - public function test_error() + public function test_retry_http_request() { $this->server->setResponseOfPath( '/' . ProductApi::PRODUCTS_URI, @@ -30,14 +29,7 @@ public function test_error() $api = $this->createClientByPassword()->getProductApi(); $response = $api->create('new_shoes', []); - - - for ($i = 0; $i < 5; $i++) { - $this->server->getRequestByOffset($i); - VarDumper::dump($this->server->getRequestByOffset(0)); - - Assert::assertSame(201, $response); - } + Assert::assertSame(201, $response); } protected function createClientByPassword(): AkeneoPimClientInterface From e8e65dbe3001670f97d4c93bc8fba4a3007b37a5 Mon Sep 17 00:00:00 2001 From: Samuel Gomis Date: Fri, 11 Aug 2023 11:04:20 +0200 Subject: [PATCH 3/4] feat(DX-160): fix --- src/Client/HttpClient.php | 4 +--- tests/Api/AkeneoPimClientBuilderTest.php | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Client/HttpClient.php b/src/Client/HttpClient.php index 1cc101a7..0e06d845 100644 --- a/src/Client/HttpClient.php +++ b/src/Client/HttpClient.php @@ -76,9 +76,7 @@ public function sendRequest(string $httpMethod, $uri, array $headers = [], $body { $request = $this->prepareRequest($httpMethod, $uri, $headers, $body); - $response = $this->httpClient->sendRequest($request); - - $response = $this->retry($response, $request); + $response = $this->retry($this->httpClient->sendRequest($request), $request); return $this->httpExceptionHandler->transformResponseToException($request, $response); } diff --git a/tests/Api/AkeneoPimClientBuilderTest.php b/tests/Api/AkeneoPimClientBuilderTest.php index 12981b32..15fd1f8e 100644 --- a/tests/Api/AkeneoPimClientBuilderTest.php +++ b/tests/Api/AkeneoPimClientBuilderTest.php @@ -9,6 +9,7 @@ use Akeneo\Pim\ApiClient\Api\ProductApi; use donatj\MockWebServer\Response; use donatj\MockWebServer\ResponseStack; +use ECSPrefix202306\Symfony\Component\VarDumper\VarDumper; use PHPUnit\Framework\Assert; final class AkeneoPimClientBuilderTest extends ApiTestCase From 74cfcac7c7372c9b348efcb6ad52155bf01fc088 Mon Sep 17 00:00:00 2001 From: Samuel Gomis Date: Fri, 11 Aug 2023 11:04:53 +0200 Subject: [PATCH 4/4] feat(DX-160): fix --- src/Client/HttpClient.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Client/HttpClient.php b/src/Client/HttpClient.php index 0e06d845..a040ffb1 100644 --- a/src/Client/HttpClient.php +++ b/src/Client/HttpClient.php @@ -2,8 +2,6 @@ namespace Akeneo\Pim\ApiClient\Client; -use Akeneo\Pim\ApiClient\Exception\TooManyRequestsHttpException; -use ECSPrefix202306\Symfony\Component\VarDumper\VarDumper; use GuzzleHttp\Promise\PromiseInterface; use Http\Promise\Promise; use Psr\Http\Message\RequestFactoryInterface; @@ -11,7 +9,6 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\StreamInterface; -use function ECSPrefix202306\dd; /** * Http client to send a request without any authentication.