Bound every connect attempt at 10 s by default, with false the way to opt out
Mirror / push (push) Successful in 5s
Test / lint (pull_request) Successful in 21s
Test / test (18) (pull_request) Successful in 19s
Test / test (20) (pull_request) Successful in 19s
Test / test (22) (pull_request) Successful in 19s
Test / test (24) (pull_request) Successful in 20s
Test / test (26) (pull_request) Successful in 19s

This commit is contained in:
2026-09-20 20:34:53 +02:00
parent 8f416c2bc4
commit 1416615ca3
8 changed files with 44 additions and 35 deletions
+18 -12
View File
@@ -524,19 +524,25 @@ rule and an index of the titles below.
`LinkGate`'s hold is not — it is awaited with no other handle, so a process whose only work is
`client()` would exit unbound.
- **`connectTimeout` is absent by default, bounds the whole connect including the TLS handshake, and
`0` is refused.** Maintainer's call, 2026-09-20, serving goal 6: a connect that never returns is
one `reconnect` cannot retry, because the operating system holds the attempt for around 130 s at
Linux's default `tcp_syn_retries` and nothing above it is counting. Absent is how that wait stays
the operating system's, so a call passing no options is unchanged, and `0` would be a second
spelling for absent — refused at the call, naming the spelling that turns it off. What expires is
reported as the ordinary connect failure, so the loop retries it like any other. It settles on
- **`connectTimeout` defaults to 10 s, bounds the whole connect including the TLS handshake, and
`false` is the one way to turn it off.** Maintainer's call, 2026-09-20, serving goal 5: a connect
that never returns is one `reconnect` cannot retry, because the operating system holds the attempt
for around 130 s at Linux's default `tcp_syn_retries` and nothing above it is counting — and no
application chooses that, so it is a default rather than an option that switches on what the caller
obviously wanted. Accepted: the far end sees roughly four times the SYNs against a dead host, one
per ~40 s rather than one per ~160 s, which goal 4 tolerates because the backoff still caps the
rate. `false` spells the operating system's wait, as it does for `reconnect`, and `0` is refused
naming it, so one spelling reaches each result. What expires is reported as the ordinary connect
failure, so the loop retries it like any other, and the message names the peer and whether the TCP
connect or the TLS handshake stalled — different faults, different answers. It settles on
`secureConnect` for a TLS socket, so a peer that accepts and then says nothing is bounded the same
way a black-holed SYN is. Rejected: `socket.setTimeout()`, an idle timeout that goes on arming
once the link is up. Rejected: bounding it with `responseTimeout`, which names the wait for an
answer on a link that already exists and would retune both at once. `server()` shares the checker
and ignores the option, as it already ignores `reconnect` — nothing at that end connects out. Open
while it has no default: whether a later major gives it one.
way a black-holed SYN is. Rejected: shipping the option with no default, which left goal 5's "an
option does not switch on the thing the caller obviously wanted" unmet, and would have cost a
second breaking minor plus a reversal of the `0` spelling to correct later. Rejected:
`socket.setTimeout()`, an idle timeout that goes on arming once the link is up. Rejected: bounding
it with `responseTimeout`, which names the wait for an answer on a link that already exists and
would retune both at once. `server()` shares the checker and ignores the option, as it already
ignores `reconnect` — nothing at that end connects out.
- **A stream this library cannot frame is a dead link; one PDU it cannot parse is not.**
Maintainer's call, 2026-08-31, narrowed 2026-09-05 via the interop plan: a `command_length` below