Skip to content

Commit

Permalink
Add retry with exponential backoff to manifest:validate
Browse files Browse the repository at this point in the history
  • Loading branch information
flavioheleno committed Jul 5, 2023
1 parent abd8a6f commit 6da9d3a
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 3 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1",
"psr/log": "^3.0",
"stechstudio/backoff": "^1.2",
"symfony/console": "^6.2",
"symfony/expression-language": "^6.3",
"symfony/filesystem": "^6.2",
Expand Down
45 changes: 44 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions config/dependencies.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use STS\Backoff\Backoff;
use STS\Backoff\Strategies\ExponentialStrategy;
use Symfony\Component\Filesystem\Path;

return static function (ContainerBuilder $builder): void {
$builder->addDefinitions(
[
Backoff::class => static function (ContainerInterface $container): Backoff {
return new Backoff(10, new ExponentialStrategy(750), 10000, true);
},
ConfigurationInterface::class => static function (ContainerInterface $container): ConfigurationInterface {
// config schema
$config = new Configuration(
Expand Down
68 changes: 66 additions & 2 deletions src/Commands/Manifest/ValidateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use Jay\Json;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;
use STS\Backoff\Backoff;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -18,12 +20,14 @@
use Symfony\Component\ExpressionLanguage\SyntaxError;
use Symfony\Component\Filesystem\Path;
use Teapot\StatusCode\Http;
use Throwable;

#[AsCommand('manifest:validate', 'Validate the analysis report using expression-based rules')]
final class ValidateCommand extends Command {
private ClientInterface $client;
private RequestFactoryInterface $requestFactory;
private StreamFactoryInterface $streamFactory;
private Backoff $backoff;

protected function configure(): void {
$this
Expand All @@ -45,6 +49,13 @@ protected function configure(): void {
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Rule expression to be evaluated and process report contents'
)
->addOption(
'retry',
null,
InputOption::VALUE_REQUIRED,
'Number of times to attempt retrieving report data before giving up',
3
)
->addArgument(
'reportId',
InputArgument::REQUIRED,
Expand Down Expand Up @@ -185,6 +196,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::FAILURE;
}

$retry = (int)$input->getOption('retry');
if ($retry < 0) {
$output->writeln('Retry must be a positive integer');

return Command::FAILURE;
}

$this->backoff->setMaxAttempts($retry);

$variables = [];
// async it!
foreach ($endpoints as $endpoint) {
Expand All @@ -200,7 +220,49 @@ protected function execute(InputInterface $input, OutputInterface $output): int
'GET',
"https://api.kahu.app/v0/reports/{$reportId}/{$endpoint}"
);
$response = $this->client->sendRequest($request);

$response = $this->backoff
->setDecider(
static function (
int $attempt,
int $maxAttempts,
ResponseInterface $response = null,
Throwable $exception = null
): bool {
if (
$attempt >= $maxAttempts ||
$response->getStatusCode() === Http::OK ||
$response->getStatusCode() >= Http::NOT_FOUND
) {
return false;
}

return true;
}
)
->setErrorHandler(
static function (
?Throwable $exception,
int $attempt,
int $maxAttempts
) use ($output, $endpoint): void {
$output->writeln(
sprintf(
'Retrieving data from api.kahu.app: %s (attempt %d of %d)',
$endpoint,
$attempt + 1,
$maxAttempts
),
OutputInterface::OUTPUT_NORMAL | OutputInterface::VERBOSITY_DEBUG
);
}
)
->run(
function () use ($request): ResponseInterface {
return $this->client->sendRequest($request);
}
);

if ($response->getStatusCode() !== Http::OK) {
$output->writeln(
sprintf(
Expand Down Expand Up @@ -251,13 +313,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
public function __construct(
ClientInterface $client,
RequestFactoryInterface $requestFactory,
StreamFactoryInterface $streamFactory
StreamFactoryInterface $streamFactory,
Backoff $backoff
) {
parent::__construct();

$this->client = $client;
$this->requestFactory = $requestFactory;
$this->streamFactory = $streamFactory;
$this->backoff = $backoff;
}
}

0 comments on commit 6da9d3a

Please sign in to comment.