Skip to content

fix(client): log dropped fire-and-forget sends in listeners hot loop#479

Merged
intendednull merged 1 commit into
claude/friendly-maxwell-bVlpWfrom
auto-fix/issue-253-warn-if-err
Apr 28, 2026
Merged

fix(client): log dropped fire-and-forget sends in listeners hot loop#479
intendednull merged 1 commit into
claude/friendly-maxwell-bVlpWfrom
auto-fix/issue-253-warn-if-err

Conversation

@intendednull
Copy link
Copy Markdown
Owner

Summary

  • Adds a private warn_if_err<T, E: Debug>(Result<T, E>, &'static str) helper in crates/client/src/listeners.rs that logs tracing::warn!(?e, "{context}") on Err and drops the success value.
  • Replaces 16 trailing .ok(); swallows in the same file with warn_if_err(...) calls, each given a distinct, diagnostic context string naming the specific call site.
  • Leaves the single .ok() at the GrantPermission branch alone — it's Result<Event, _> -> Option<Event> coercion fed into if let Some(event) = ..., not a fire-and-forget send.

Previously a dead broker or broken topic would silently lose every subsequent event with no log. The listener still proceeds on failure (a downstream send issue should not abort the loop), but field logs now surface the failure with enough context to root-cause.

Helper is private to listeners.rs. No propagation to other crates — issue #253 is scoped to this hot loop; broader audit is a separate scope decision.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy -p willow-client --all-targets -- -D warnings
  • cargo test -p willow-client — 287 passed, 0 failed
  • cargo check -p willow-client --target wasm32-unknown-unknown

Refs #253


Generated by Claude Code

Replaces 16 trailing `.ok();` swallows in `crates/client/src/listeners.rs`
with a private `warn_if_err(Result<T, E>, &'static str)` helper that emits
`tracing::warn!(?e, "{context}")` on `Err` and drops the success value.

Previously, when the broker stopped or a topic broadcast failed, the
listener silently kept running with no record. With this change the
listener still proceeds (a downstream send failure should not abort the
loop), but field logs now surface the issue with a diagnostic context
string that names the specific call site.

Migrated sites span:
- `event_broker.do_send(Publish(...))` for PeerConnected / PeerDisconnected
  / derived ClientEvent / ProfileUpdated / SyncCompleted / VoiceJoined /
  VoiceLeft / VoiceSignal / JoinLinkResponse / JoinLinkDenied
- `topic.broadcast(...)` for SyncBatch (SyncRequest reply), JoinResponse,
  Event(GrantPermission)
- `persistence.do_send(PersistEvent { ... })` for both the inline DAG-apply
  loop and the GrantPermission branch

One `.ok()` site at line 573 is intentionally left as-is: it converts a
`Result<Event, _>` from `ds.managed.create_and_insert(...)` to an
`Option<Event>` consumed by the surrounding `if let Some(event) = ...`.
That is `Result -> Option` coercion, not a swallowed fire-and-forget
send, so the helper does not apply.

Helper lives in `listeners.rs` only; no propagation to other files —
issue #253 is scoped to this hot loop. A separate audit can decide
whether other crates' `.ok();` sites warrant the same treatment.

Refs #253
@intendednull intendednull merged commit f2b6446 into claude/friendly-maxwell-bVlpW Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants