Do not use up retries on requests which timed out during a prompt
Nothing drives the transfers while tick() is blocked, e.g. by a prompt for credentials, so requests which are still connecting time out with curl error 28. Since #12662 these are retried, but each retry counts like any other, so a few prompts can use up all of them, and parallel requests to a private host which timed out that way abort with "Invalid credentials" once the first of them got credentials, as AuthHelper only reuses those for a request which was not retried yet. tick() now keeps track of how long it was blocked between two ticks, and a request which spent most of its time in that gap is restarted without counting towards maxRetries. Fixes #12402
This commit is contained in:
1 parent
44656d3be2
commit
17d32b7184
2 files changed
+52
No files matched your search
@@ -200,6 +200,38 @@ class CurlDownloaderTest extends TestCase
|
||||
self::assertSame([], $this->readProperty($downloader, 'jobs'), 'a cancelled request must not be sent again');
|
||||
}
|
||||
|
||||
public function testTimeoutWhileTheLoopWasBlockedDoesNotUseUpARetry(): void
|
||||
{
|
||||
// the kernel accepts the connection but nothing ever answers, so the request can only time out
|
||||
$server = stream_socket_server('tcp://127.0.0.1:0');
|
||||
self::assertIsResource($server);
|
||||
$address = stream_socket_get_name($server, false);
|
||||
self::assertIsString($address);
|
||||
|
||||
$downloader = $this->createDownloader();
|
||||
$failure = null;
|
||||
// a request which has no retries left, e.g. after timing out during earlier prompts
|
||||
self::callPrivate($downloader, 'initDownload', static function (): void {
|
||||
}, static function (\Exception $e) use (&$failure): void {
|
||||
$failure = $e->getMessage();
|
||||
}, $address, 'http://'.$address.'/packages.json', ['http' => ['timeout' => 1]], null, ['retries' => 3]);
|
||||
|
||||
$downloader->tick();
|
||||
// a prompt for credentials keeps tick() from being called for longer than the request may take
|
||||
usleep(1500000);
|
||||
$downloader->tick();
|
||||
|
||||
self::assertNull($failure);
|
||||
$jobs = $this->readProperty($downloader, 'jobs');
|
||||
self::assertIsArray($jobs);
|
||||
self::assertCount(1, $jobs, 'the request must have been sent again');
|
||||
|
||||
foreach (array_keys($jobs) as $id) {
|
||||
$downloader->abortRequest((int) $id);
|
||||
}
|
||||
fclose($server);
|
||||
}
|
||||
|
||||
public function testRetryWaitsForTheLatestRetryAfterOfItsOrigin(): void
|
||||
{
|
||||
$io = new BufferIO();
|
||||
|
||||
Reference in new issue
Block a user