Commit d8cb143
authored
fix(server): configurable HTTP timeouts + don't evict upstream on call-scoped cancellation (#968)
* fix(server): configurable HTTP timeouts + don't evict upstream on call-scoped cancellation (GH #965)
Part 1: http_read_timeout / http_write_timeout / http_idle_timeout config
keys (tri-state *Duration; 0 = no deadline; restart-required; env
overridable). The write-timeout default changes from a hardcoded 120s to
0: a write deadline is a wall-clock cap on the whole response, so it
truncated any tool call slower than 2 minutes and silently killed SSE
/events streams. Slowloris protection stays via the 60s ReadHeaderTimeout.
Part 2: managed.Client.CallTool no longer treats call-scoped context
cancellation as proof of a dead server. Caller-ctx cancellation never
evicts; ambiguous wrapped cancellations trigger one gated async liveness
probe (probe failure = the hard evidence that does evict); genuine
transport errors (refused/reset/broken pipe) evict immediately as before.
* fix(server): review round 2 — per-route deadline exemption, probe hardening (GH #965)
- Restore the 120s write-timeout default; instead of disabling it globally,
the streaming routes (/mcp*, /v1/tool_code*, /events) clear their
per-request write deadline (and read deadline for body-less GET/HEAD)
via http.ResponseController. Long tool calls and SSE work out of the
box while REST/UI/health keep slow-reader protection.
- Ambiguous-cancellation probe now follows the health loop's policy:
only hard transport evidence evicts; transient/non-connection ping
failures defer to the background health loop's 3-strike threshold.
- connectionEpoch guards the detached probe against SetError-ing a
session that reconnected while the probe was in flight.
- ReloadConfiguration warns when a file edit touches restart-required
fields (pre-existing silent gap, now visible).
- Per-field swagger doc comments so all three http_*_timeout keys are
documented in the OAS spec.
* fix(server): review round 3 — close epoch TOCTOU, document idle-timeout fallback (GH #965)
- Connect now bumps connectionEpoch BEFORE exposing Ready, and both run
under epochMu, paired with the probe's final check-and-SetError — a
reconnect can no longer complete between the probe's staleness check
and its verdict, and a new session is never visible with the old epoch.
- http_idle_timeout "0s" documented accurately: net/http falls back to
ReadTimeout when IdleTimeout is 0, so idle is unbounded only when
http_read_timeout is also 0 (resolver, struct comment, all three docs,
OAS regenerated); stale hot-reload comment fixed; resolver-contract
test case added for idle-zero-alone.
* fix(server): review round 4 — TransitionTo out of epochMu, idle-fallback wording everywhere (GH #965)
- Connect no longer holds epochMu across TransitionTo(Ready): the
transition invokes its state-change callback synchronously, so the
mutex now guards only the epoch bump (still ordered before Ready;
correctness analysis in the comment). Lock invariant documented
truthfully: SetError's callback is async, TransitionTo's is not.
- Every remaining blanket '0s = no timeout' statement (docs x3, config
const + struct comments, env WARN message) now carries the
IdleTimeout→ReadTimeout fallback caveat; OAS regenerated.
* fix(server): review round 5 — Disconnect invalidates the probe epoch (GH #965)
- Disconnect now bumps connectionEpoch under epochMu before resetting the
state machine, closing the last stale-probe window: an in-flight
ambiguous-call probe can no longer flip a freshly Disconnected client
back to Error (which also burned a retry and emitted a bogus
notification). Regression test simulates the teardown ordering.
- Last two blanket '0s disables the deadline' comments (loader env sink,
config test header) now carry the IdleTimeout→ReadTimeout caveat.
* test(upstream): drive the real Disconnect in the stale-probe regression test (GH #965)
The disconnect-race test now tears down through Client.Disconnect (nil
core-client guard added, same fallback contract as toolInvoker/
healthProbe) instead of simulating the ordering. Honest coverage note:
the sub-microsecond Reset-vs-verdict interleaving is unobservable from
outside precisely because epochMu serializes it; the epoch-guard
mutation is killed by the reconnect-path test, where the epoch is the
only discriminator.1 parent 6411a5f commit d8cb143
15 files changed
Lines changed: 1479 additions & 29 deletions
File tree
- docs
- configuration
- internal
- config
- runtime
- server
- upstream/managed
- oas
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
111 | 141 | | |
112 | 142 | | |
113 | 143 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
32 | 35 | | |
33 | 36 | | |
34 | 37 | | |
| |||
59 | 62 | | |
60 | 63 | | |
61 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
62 | 84 | | |
63 | 85 | | |
64 | 86 | | |
| |||
204 | 226 | | |
205 | 227 | | |
206 | 228 | | |
| 229 | + | |
| 230 | + | |
207 | 231 | | |
208 | 232 | | |
209 | 233 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
78 | 97 | | |
79 | 98 | | |
80 | 99 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
70 | 90 | | |
71 | 91 | | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
72 | 136 | | |
73 | 137 | | |
74 | 138 | | |
| |||
227 | 291 | | |
228 | 292 | | |
229 | 293 | | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
230 | 326 | | |
231 | 327 | | |
232 | 328 | | |
| |||
2021 | 2117 | | |
2022 | 2118 | | |
2023 | 2119 | | |
| 2120 | + | |
| 2121 | + | |
| 2122 | + | |
| 2123 | + | |
| 2124 | + | |
| 2125 | + | |
| 2126 | + | |
| 2127 | + | |
| 2128 | + | |
| 2129 | + | |
| 2130 | + | |
| 2131 | + | |
2024 | 2132 | | |
2025 | 2133 | | |
2026 | 2134 | | |
| |||
0 commit comments