feat: retries of api requests in case of failure
This commit is contained in:
parent
7eac908bc4
commit
6e5f929dc3
@ -39,6 +39,13 @@ services:
|
||||
arguments:
|
||||
$username: '%app.usetreno.username%'
|
||||
$password: '%app.usetreno.password%'
|
||||
$retryCount: 2
|
||||
$retryWaitSeconds: 0.5
|
||||
|
||||
App\Service\Remote\UsetrenoQRCodeProvider:
|
||||
arguments:
|
||||
$retryCount: 2
|
||||
$retryWaitSeconds: 0.5
|
||||
|
||||
App\Service\CachedQRCodeGenerator:
|
||||
arguments:
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Remote\Usetreno;
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Remote\Exception;
|
||||
|
||||
class UsetrenoQRCodeRemoteServerErrorException extends UsetrenoQRCodeException
|
||||
{
|
||||
|
||||
}
|
@ -5,7 +5,9 @@ namespace App\Service\Remote;
|
||||
|
||||
use App\Entity\Remote\Usetreno\AuthRequest;
|
||||
use App\Service\Remote\Exception\AuthorizeException;
|
||||
use Nubium\Exception\ThisShouldNeverHappenException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
@ -16,12 +18,16 @@ use Symfony\Contracts\HttpClient\ResponseStreamInterface;
|
||||
|
||||
class UsetrenoHttpClient implements HttpClientInterface
|
||||
{
|
||||
use RetryingFailClientTrait;
|
||||
|
||||
const AUTHORIZE_API = "https://topapi.top-test.cz/chameleon/api/v1/token";
|
||||
|
||||
protected ?string $authorizationToken = null;
|
||||
|
||||
public function __construct(protected HttpClientInterface $innerClient, protected readonly LoggerInterface $logger, protected readonly string $username,
|
||||
protected readonly string $password) { }
|
||||
protected readonly string $password,
|
||||
protected readonly float $retryWaitSeconds,
|
||||
protected readonly int $retryCount) { }
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
@ -88,26 +94,35 @@ class UsetrenoHttpClient implements HttpClientInterface
|
||||
"AUTHORIZE_API" => static::AUTHORIZE_API
|
||||
]);
|
||||
|
||||
$rq = $this->innerClient->request(
|
||||
"POST",
|
||||
static::AUTHORIZE_API,
|
||||
[
|
||||
'json' => new AuthRequest($this->username, $this->password),
|
||||
]
|
||||
);
|
||||
$responseData = $this->retryingFailRequest($this->retryCount, $this->retryWaitSeconds,
|
||||
[AuthorizeException::class, TransportException::class], $this->logger, function() {
|
||||
$rq = $this->innerClient->request(
|
||||
"POST",
|
||||
static::AUTHORIZE_API,
|
||||
[
|
||||
'json' => new AuthRequest($this->username, $this->password),
|
||||
]
|
||||
);
|
||||
|
||||
$statusCode = $rq->getStatusCode();
|
||||
$responseData = $rq->getContent(false);
|
||||
$statusCode = $rq->getStatusCode();
|
||||
$responseData = $rq->getContent(false);
|
||||
|
||||
if ($statusCode != 200) {
|
||||
$this->logger->error("authorization request status code is not ok", [
|
||||
"AUTHORIZE_API" => static::AUTHORIZE_API,
|
||||
"statusCode" => $statusCode,
|
||||
"content" => $responseData,
|
||||
"username" => $this->username
|
||||
]);
|
||||
if ($statusCode != 200) {
|
||||
$this->logger->error("authorization request status code is not ok", [
|
||||
"AUTHORIZE_API" => static::AUTHORIZE_API,
|
||||
"statusCode" => $statusCode,
|
||||
"content" => $responseData,
|
||||
"username" => $this->username
|
||||
]);
|
||||
|
||||
throw new AuthorizeException("Return code is not 200 OK (got: code: $statusCode)");
|
||||
throw new AuthorizeException("Return code is not 200 OK (got: code: $statusCode)");
|
||||
}
|
||||
|
||||
return $responseData;
|
||||
});
|
||||
|
||||
if (!is_string($responseData)) {
|
||||
throw new ThisShouldNeverHappenException("responseData is not a string");
|
||||
}
|
||||
|
||||
$this->authorizationToken = $this->processAuthorizeResponse($responseData);
|
||||
|
@ -7,16 +7,23 @@ use App\Entity\DTO\QRCode\QRCode;
|
||||
use App\Service\CacheableQRCodeGeneratorInterface;
|
||||
use App\Service\Remote\Edge\QRCodeEntityConverter;
|
||||
use App\Service\Remote\Exception\UsetrenoQRCodeException;
|
||||
use App\Service\Remote\Exception\UsetrenoQRCodeRemoteServerErrorException;
|
||||
use Nubium\Exception\ThisShouldNeverHappenException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||
|
||||
class UsetrenoQRCodeProvider implements CacheableQRCodeGeneratorInterface
|
||||
{
|
||||
use RetryingFailClientTrait;
|
||||
|
||||
const QRCODE_API = 'https://topapi.top-test.cz/chameleon/api/v1/qr-code/create-for-bank-account-payment';
|
||||
const QRCODE_METHOD = 'POST';
|
||||
|
||||
public function __construct(protected readonly LoggerInterface $logger,
|
||||
protected readonly UsetrenoHttpClient $client,
|
||||
protected readonly QRCodeEntityConverter $codeEntityConverter) { }
|
||||
protected readonly QRCodeEntityConverter $codeEntityConverter,
|
||||
protected readonly float $retryWaitSeconds,
|
||||
protected readonly int $retryCount) { }
|
||||
|
||||
public function generateQRCodeFromEntity(QRCode $entity): string
|
||||
{
|
||||
@ -27,27 +34,41 @@ class UsetrenoQRCodeProvider implements CacheableQRCodeGeneratorInterface
|
||||
"edgeEntity" => $edgeEntity
|
||||
]);
|
||||
|
||||
$response = $this->client->request(static::QRCODE_METHOD, static::QRCODE_API, [
|
||||
'json' => $edgeEntity,
|
||||
]);
|
||||
$responseData = $this->retryingFailRequest($this->retryCount, $this->retryWaitSeconds,
|
||||
[TransportException::class, UsetrenoQRCodeRemoteServerErrorException::class], $this->logger,
|
||||
function() use ($edgeEntity) {
|
||||
$response = $this->client->request(static::QRCODE_METHOD, static::QRCODE_API, [
|
||||
'json' => $edgeEntity,
|
||||
]);
|
||||
|
||||
$statusCode = $response->getStatusCode();
|
||||
$responseData = $response->getContent(false);
|
||||
$statusCode = $response->getStatusCode();
|
||||
$responseData = $response->getContent(false);
|
||||
|
||||
if ($statusCode != 200) {
|
||||
$this->logger->error("qrcode request status code is not ok", [
|
||||
"AUTHORIZE_API" => static::QRCODE_API,
|
||||
"statusCode" => $statusCode,
|
||||
"content" => $responseData,
|
||||
]);
|
||||
if ($statusCode != 200) {
|
||||
$this->logger->error("qrcode request status code is not ok", [
|
||||
"AUTHORIZE_API" => static::QRCODE_API,
|
||||
"statusCode" => $statusCode,
|
||||
"content" => $responseData,
|
||||
]);
|
||||
|
||||
throw new UsetrenoQRCodeException("Return code is not 200 OK (got: code: $statusCode)");
|
||||
if ($statusCode > 500) {
|
||||
throw new UsetrenoQRCodeRemoteServerErrorException("Return code is not 200 OK (got: code: $statusCode)");
|
||||
}
|
||||
|
||||
throw new UsetrenoQRCodeException("Return code is not 200 OK (got: code: $statusCode)");
|
||||
}
|
||||
|
||||
$this->logger->debug("QRCode generation success", [
|
||||
"responseContent" => $responseData,
|
||||
]);
|
||||
|
||||
return $responseData;
|
||||
});
|
||||
|
||||
if (!is_string($responseData)) {
|
||||
throw new ThisShouldNeverHappenException("responseData is not a string");
|
||||
}
|
||||
|
||||
$this->logger->debug("QRCode generation success", [
|
||||
"responseContent" => $responseData,
|
||||
]);
|
||||
|
||||
|
||||
return $this->parseBase64String($this->processQRCodeResponseEntity($responseData));
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ class UsetrenoHttpClientTest extends TestCase
|
||||
]);
|
||||
$authorizedRequestResponse = clone $authMockResponse;
|
||||
$mockedClient = new MockHttpClient([$authMockResponse, $authorizedRequestResponse]);
|
||||
$client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar");
|
||||
$client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar", 0, 0);
|
||||
$client->request("POST", "https://www.root.cz/");
|
||||
$this->assertEquals("https://topapi.top-test.cz/chameleon/api/v1/token", $authMockResponse->getRequestUrl());
|
||||
$headers = $authorizedRequestResponse->getRequestOptions()['headers'];
|
||||
@ -48,7 +48,7 @@ class UsetrenoHttpClientTest extends TestCase
|
||||
|
||||
$authorizedRequestResponse = clone $authMockResponse;
|
||||
$mockedClient = new MockHttpClient([$authMockResponse, $authorizedRequestResponse]);
|
||||
$client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar");
|
||||
$client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar", 0, 0);
|
||||
$client->request("POST", "https://www.root.cz/");
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class UsetrenoQRCodeProviderTest extends TestCase
|
||||
->method('convert')
|
||||
->will($this->returnValue($edgeEntity));
|
||||
|
||||
return new UsetrenoQRCodeProvider($this->getLogger(), $mock, $converterMock);
|
||||
return new UsetrenoQRCodeProvider($this->getLogger(), $mock, $converterMock, 0, 0);
|
||||
}
|
||||
|
||||
protected function createQRCodeEntityPair() {
|
||||
|
Loading…
Reference in New Issue
Block a user