[Client] Implement setMaxRetries connection retries (#413)

* [Client] Implement setMaxRetries connection retries

* [Client] Reject a negative retry count in Configuration

* [Client] Use a positive init timeout in the retry test

* [Client] Drop redundant docblock note on setMaxRetries

* [Client] Clear the initialized flag on a failed connection

* [Client] Trim comments to the non-obvious ones

* [Client] Cover retries and timeout cleanup with integration tests

The retry fixture counts the processes it was started as, which is what
separates a real retry from a second call into the same server. The timeout
fixture outlives the client's patience and then goes idle, so the next
request runs on a connection the client already gave up on once.
This commit is contained in:
Christopher Hertel 2026-08-15 02:43:50 +02:00 • committed by GitHub
commit d8cc21a345
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -55,26 +55,42 @@ abstract class IntegrationTestCase extends TestCase
*/
protected function connect(string $fixture, ?ClientBuilder $client = null, array $env = []): Client
{
$script = __DIR__.'/Fixture/'.$fixture.'.php';
$this->client = ($client ?? $this->clientBuilder())->build();
try {
$this->client->connect(new StdioTransport(
command: \PHP_BINARY,
args: [$script],
// proc_open() replaces the environment rather than adding to it.
env: [] === $env ? null : array_merge(getenv(), $env),
));
$this->client->connect($this->transport($fixture, $env));
} catch (ConnectionException $e) {
// The transport discards the child's stderr, so a fixture dying on
// startup arrives here as a bare timeout.
$this->fail(\sprintf('Could not connect to fixture server "%s": %s. Run `%s %s` to see why.', $fixture, $e->getMessage(), \PHP_BINARY, $script));
$this->fail(\sprintf('Could not connect to fixture server "%s": %s. Run `%s %s` to see why.', $fixture, $e->getMessage(), \PHP_BINARY, self::script($fixture)));
}
return $this->client;
}
/**
* A transport that will spawn a fixture server, without connecting it.
*
* Tests that assert on a failing connection need the transport by itself,
* since {@see self::connect()} turns that failure into a test failure.
*
* @param array<string, string> $env added to the server process environment
*/
protected function transport(string $fixture, array $env = []): StdioTransport
{
return new StdioTransport(
command: \PHP_BINARY,
args: [self::script($fixture)],
// proc_open() replaces the environment rather than adding to it.
env: [] === $env ? null : array_merge(getenv(), $env),
);
}
private static function script(string $fixture): string
{
return __DIR__.'/Fixture/'.$fixture.'.php';
}
protected function tearDown(): void
{
$this->client?->disconnect();