fix(runtime): report TCP broadcast write failures with -1 and errno#2671
Open
slepp wants to merge 2 commits into
Open
fix(runtime): report TCP broadcast write failures with -1 and errno#2671slepp wants to merge 2 commits into
slepp wants to merge 2 commits into
Conversation
hew_tcp_broadcast_except silently skipped per-recipient clone and write failures: when every eligible write failed it returned 0, and the stdlib lifted that to Ok(0) — indistinguishable from having no recipients at all. Callers could acknowledge or discard messages under a false-success result. Delivery stays best-effort: every eligible recipient is still attempted so one dead peer never denies the healthy ones. The function now records the first failing operation's message and OS errno in the shared thread-local (the same set_last_error_with_errno channel hew_tcp_write uses, emitted after the table lock is released) and returns -1 when any eligible recipient failed. Zero eligible recipients remains a clean 0, and try_broadcast_except's existing n < 0 mapping to NetError now actually fires. Failed streams are deliberately not evicted from the connection table: removal belongs to hew_tcp_close and the reactor detach path, and a transient backpressure failure must not change connection lifecycle. Regression tests cover all-recipients-fail, partial failure (healthy peer still receives the message, broadcast still reports -1), the delivered count with an excluded connection, zero eligible recipients, and a deterministic clone failure via RLIMIT_NOFILE. Fixes #2657
broadcast_except and try_broadcast_except now surface the runtime's fail-closed broadcast contract: the delivered count on full success, 0 when there is nothing to deliver to, and -1 (mapped to NetError by try_broadcast_except) when any eligible connection's write failed while healthy connections were still delivered to. No logic change — try_broadcast_except's errno-to-NetError mapping already handled a negative result; the runtime just never produced one for per-recipient failures before.
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.
Why
hew_tcp_broadcast_exceptsilently swallowed per-recipient write failures: a dead peer, a failed stream clone, or a partial write left the loop withcontinueand the function still returned a success-shaped recipient count. Thetry_broadcast_exceptwrapper instd/net/net.hewalready declared ann < 0 → NetErrorpath, but the runtime could never produce a negative return, so callers had no way to observe delivery failures.What
-1when any eligible recipient failed (errno recorded),0when there were zero eligible recipients, delivered count otherwise. All three failure branches (stream clone, body write, newline write) feed the same accounting.try_broadcast_except/broadcast_exceptnow describe the tri-state contract and the failure mapping; no behaviour change in the wrappers — the existingNetErrorpath simply fires now.Test
Five new regression tests in
hew-runtime/src/transport.rs, run in isolated processes where they mutate process-global state (SIGPIPE disposition, RLIMIT_NOFILE):broadcast_all_recipients_failed_returns_minus_one_with_errno— deterministic peer RST, asserts-1+ non-zero errnobroadcast_partial_failure_returns_minus_one_and_still_delivers— one dead + one healthy peer; healthy peer receives the full frame, return is-1broadcast_clone_failure_records_errno_and_message— fd-limit-induced clone failure, asserts the clone-branch message prefix + errnobroadcast_zero_eligible_recipients_returns_zero— pins0(clean no-op) as distinct from-1, no errno recordedbroadcast_success_returns_delivered_count— happy-path count unchangedEach failure assertion (
== -1+ recorded errno) is unproducible by the old code, which could only returnrecipients >= 0.Quality Checklist
.ok()?orunwrap_or_default()in codegen without// JUSTIFIEDcomment// WASM-TODO(#NNN):marker, and newhew_*exports are classified inscripts/jit-symbol-classification.toml(no new exports; existing symbol's return semantics documented)hew_tcp_write)Out of scope
hew_tcp_write,hew_tcp_close, and the reactor paths are untouched.Fixes #2657