Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Max_duration is not respected when retry_count > 1 (http-client) #46316

Copy link
Copy link
Closed
@r-martins

Description

@r-martins
Issue body actions

Symfony version(s) affected

5.4.8

Description

Let's say you have an API endpoint that always fails on the first request, and succeed on the second attempt.
Every request takes 30 seconds to be returned by the API.

If you make a Retryable HttpRequest, you can define timeout and max_duration to 40 seconds.
But it will not be respected, because when doing the second attempt, symfony still waits up to 40 seconds to get a response.

So you can expect this part of code to take 60 seconds to respond with no issues, instead of having a timeout error.

How to reproduce

  1. Create the following sleep.php file:
<?php
sleep(30);
$count = (int)@file_get_contents('.count') == 0 ? 1 : (int)@file_get_contents('.count');
if ($count >= 2) {
    unlink('.count');
    echo '2nd attempt. SUCCESS!';
    exit;
}
$count++;
http_response_code(502);
echo 'Failed. ' . $count-1 . ' attempt;';
file_put_contents('.count', (string)$count);
  1. Run php -S localhost:8888 in the folder of the file above
  2. Create a Command to test it:
<?php
#src/TestCommand.php
namespace App;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class TestCommand extends \Symfony\Component\Console\Command\Command
{
    protected static $defaultName = 'app:test';
    
    public function __construct(protected HttpClientInterface $httpClient, string $name = null)
    {
        parent::__construct($name);
    }
    
    protected function configure()
    {
        parent::configure(); // TODO: Change the autogenerated stub
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        $output->writeln('Start: ' . date('H:i:s'));
        $start = time();
        $url = 'http://localhost:8888/sleep.php';
        $client = $this->httpClient;
        $response = $client->request('GET', $url, [
            'timeout' => 40,
            'max_duration' => 40
        ]);


        try {
            $output->writeln($response->getStatusCode().': '.$response->getContent(false));
        } catch (ClientExceptionInterface $e) {
            $output->writeln(get_class($e) . ': ' . $e->getMessage());
        } catch (RedirectionExceptionInterface $e) {
            $output->writeln(get_class($e) . ': ' . $e->getMessage());
        } catch (ServerExceptionInterface $e) {
            $output->writeln(get_class($e) . ': ' . $e->getMessage());
        } catch (TransportExceptionInterface $e) {
            $output->writeln(get_class($e) . ': ' . $e->getMessage());
        }
        $output->writeln('Retry coint: ' . (int)$response->getInfo('retry_count'));
        $output->writeln('End: ' . date('H:i:s'));
        $output->writeln('Total time: ' . time()-$start . 's');
        return 1;
    }
}
  1. Run the test comand with bin/console app:test and note that it will succeed on the second attempt after 60 seconds.

Possible Solution

We may need to work on AmpHttpClient or RetryableHttpClient to use the time left on the other requests.

I posted a half solution here that may be useful to get the total time of the request, including the waiting time between the attempts.

But it's far from the ideal solution.

Additional Context

In my case, I have a controller that makes http requests to another endpoint.
The users that call this controller, expect it to return a response in 45 seconds. However, after implementing the RetryableHttpClient, I'm having cases where the request is processed by the other endpoint in the second or third attempt, but my users get a timeout exception.

It happens because the first request to the other endpoint takes less than 45 seconds, but both calls take more than that.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.