[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

@ -57,10 +57,32 @@ $client = Client::builder()
->setClientInfo('My Application', '1.0.0', 'Description of my client')
->setInitTimeout(30) // Seconds to wait for initialization
->setRequestTimeout(120) // Seconds to wait for request responses
->setMaxRetries(3) // Retry attempts for failed connections
->setMaxRetries(3) // Retries for failed connections
->build();
```
### Connection Retries
`setMaxRetries()` controls how often `connect()` retries a failed connection. It
counts retries rather than attempts, so the default of `3` means one initial
attempt plus up to three retries — four in total — before the `ConnectionException`
of the last attempt is rethrown:
```php
$client = Client::builder()
->setMaxRetries(0) // Fail on the first failed attempt
->build();
```
Between two attempts the transport is closed, so a retry never reuses a
half-established connection: a `StdioTransport` spawns a fresh server process and
an `HttpTransport` discards the session ID of the failed attempt. Each retry is
preceded by a short, linearly growing delay (100ms, 200ms, 300ms, …).
Only the connection handshake is retried. Individual requests such as
`callTool()` are always sent once — retrying them is unsafe as tool calls are not
necessarily idempotent.
### Client Information
Set the client's identity reported to servers during initialization: