Add deadline, timeout, and hot-path controls to the connection loop - #7
Merged
Merged
Conversation
lpgauth
force-pushed
the
bidder-workload-features
branch
from
July 10, 2026 10:47
3baa122 to
e8306fd
Compare
Extend whitecap with the controls a latency-sensitive workload needs to honor a per-request deadline and stay resilient under load, plus two hot-path improvements. Requests now carry a `received` arrival timestamp so a handler can measure time already spent on the wire and shed against its deadline. The single `receive_timeout` is split into `keepalive_timeout` (idle wait for the next request) and `request_timeout` (per-read wait once a request has started), allowing a short in-request deadline for slowloris protection without dropping healthy idle keep-alive connections. An optional `handler_timeout` bounds handler run time, answering 504 and emitting a `[whitecap, handler, timeout]` event; it defaults to infinity and stays inline with no per-request process. Per-connection config is read once at connection start rather than on every request, and a body with a known Content-Length is read with an exact-length recv instead of repeatedly re-buffering partial reads. All new timeouts default to infinity and fall back to a set `receive_timeout`, so behaviour is unchanged unless configured.
lpgauth
force-pushed
the
bidder-workload-features
branch
from
July 24, 2026 13:50
e8306fd to
ea73b6b
Compare
The timeout branch demonitored, killed the handler, then drained its mailbox with a non-blocking receive. The kill and the handler's result travel in opposite directions, so there is no ordering between them: a result sent in the kill race can arrive after the drain and then linger forever under a fresh per-request ref. On a long-lived keep-alive connection that is a slow memory leak and, via selective-receive scanning, a creeping latency regression. Kill first, then block for either the result or the guaranteed DOWN. Same-sender signal ordering delivers a raced result before the DOWN, so both are consumed and no message is orphaned.
Document that a finite handler_timeout kills the handler with exit(kill), which does not release resources it held (pool checkouts, locks), so such handlers must be side-effect-safe.
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.
Summary
Extends whitecap with the controls a latency-sensitive workload needs to honor a per-request deadline and stay resilient under load, plus two hot-path improvements. All new timeouts default to
infinityand fall back to a setreceive_timeout, so behaviour is unchanged unless configured.#whitecap_req{}gains areceivedfield (os:system_time(), native units), stamped when the first byte arrives, so a handler can measure time already spent on the wire and shed against a deadline.receive_timeoutsplits intokeepalive_timeout(idle wait for the next request) andrequest_timeout(per-read wait once a request has started arriving). A shortrequest_timeoutgives slowloris protection without dropping healthy idle keep-alive connections.receive_timeout, if set, remains the back-compat default for both.handler_timeout(defaultinfinity). A finite value runs the handler in a monitored process; an overrun is killed and answered504, emitting[whitecap, handler, timeout].infinitykeeps the handler inline with no per-request process — the right choice when the handler enforces its own deadline.handler_timeout,keepalive_timeout,max_keepalive, andrequest_timeoutare read once at connection start rather than on every request/read.Content-Lengthis read with an exact-lengthgen_tcp:recv, landing in one read and one concat instead of repeatedly re-buffering partial reads (previously O(n²) on a body fragmented across TCP segments).Docs (README config + telemetry tables,
receivedusage note) and CHANGELOG updated under## Unreleased. No version bump.Verified: strict compile (warnings-as-errors), xref, and dialyzer clean; eunit 32 passed, including 4 new tests covering the arrival timestamp, split-body reassembly,
504on handler overrun (~100ms), and408on a stalled request (~300ms).