Repository navigation
Let a callback select a bounded per-request deadline - #7
Merged
Merged
Conversation
`timeout_ms` bounds every request cycle, including long event streams. A stream route now calls `Context.setRequestTimeout(ms)` to select a longer deadline for its own request. `Config.max_timeout_ms` bounds the value and defaults to zero, which disables the override. The scheduler adopts the value when the callback returns or flushes. Earlier unsent pipelined responses keep their deadline. A finished request restores `timeout_ms` for the idle keep-alive cycle and the next request. The reference server adds `--max-timeout-ms` and an `/extended-wait-only` route. The continuation suite checks extension, bound and reset in both execution modes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The deadline of a kept-alive request counted from the end of the preceding response. Idle time before the next request shortened that request's deadline, including an extended `setRequestTimeout` deadline. Proxies such as `tailscale serve` reuse idle backend connections, so a stream that began after 12 idle seconds of a 15-second budget ended after 3 seconds. A connection is now idle while no request byte is buffered or active. The new `Config.idle_timeout_ms` bounds that wait after accept and between requests; zero selects `timeout_ms`, the previous behavior. The first received byte ends the idle state and starts the request deadline. Two continuation groups cover a delayed request on a kept-alive connection, with and without an extended deadline, and a separate idle bound. The first group fails against the previous commit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
renerocksai
force-pushed
the
feat/request-deadline
branch
from
September 25, 2026 16:53
57b0af8 to
dae8961
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Config.timeout_msbounds every request cycle, and streaming flushes do not reset it.One value serves two needs badly.
An event stream (SSE) wants minutes, and an ordinary request wants seconds.
A large global value lets any stalled request hold a connection for the same long time.
Change
Config.max_timeout_ms(default0, disabled) bounds the longest deadline a callback may select.Validation requires
timeout_ms ≤ max_timeout_ms ≤ 24 hwhen the value is nonzero.Context.setRequestTimeout(ms)selects the deadline of the current request:msafter the request started.It returns
InvalidRequestTimeoutfor zero or values above the bound,RequestTimeoutUnavailablewhen disabled, andCancelledafter cancellation.The worker writes one slot field before the phase release, and the owner reads it after the acquire.
timeout_msfor the idle keep-alive cycle and the next request.Found with
tailscale serve, which reuses idle backend connections: with 15 s, a stream after 12 s idle ended after 3 s.Now a connection is idle while no request byte is buffered or active, and
Config.idle_timeout_msbounds that wait (0 =timeout_ms, the previous behavior).The first received byte starts the request deadline, including the one from
setRequestTimeout.The reference server gains
--max-timeout-msand/extended-wait-only.docs/USING.mddocuments the option and the method.Motivation
Baz applications such as the omajot hub serve an SSE "doorbell" next to short JSON routes.
A follow-up Baz PR exposes this as
RouteOptions.timeout_ms.Verification (exact Zig 0.16.0)
zig build verifyzig build testcontinuation_integration.py(ReleaseSafe)extended_request_deadline,idle_keep_alive_then_request,idle_timeout_is_separatein both modesidle_keep_alive_then_requestagainst the first commit96c249bintegration.py,batch,inline,gather,arena_lifecyclezig build testcontinuation_integration.pyintegration.pyWindows was not run locally; the hosted Windows workflow covers it.
Not in this PR
Graceful termination at the deadline: today the owner closes a chunked stream without the final
0\r\n\r\nchunk.Browsers reconnect, but strict clients such as
std.http.ClientreportReadFailed.A later change could deliver a final callback, or write the terminating chunk at a chunk boundary.
With a per-request deadline, an application can also finish its stream just before the deadline.
🤖 Generated with Claude Code