Skip to content

fix(bench): join the worker during shutdown - #845

Merged
0-jake-0 merged 1 commit into
wingfoil-io:mainfrom
snowyukitty:fix/bencher-clean-shutdown
Aug 15, 2026
Merged

0-jake-0 merged 1 commit into
wingfoil-io:mainfrom
snowyukitty:fix/bencher-clean-shutdown

Conversation

@snowyukitty

Copy link
Copy Markdown
Contributor

What this changes

Keep the bencher worker's JoinHandle and join it during orderly shutdown. A runner exit caused by Kill is treated as expected, while a worker panic is resumed on the caller thread.

Why

The worker was spawned and detached, so benchmark shutdown could return while it was still alive. Joining it makes teardown deterministic and avoids logging the intentional kill signal as an error.

Closes #833.

How it was verified

  • cargo fmt --all
  • cargo lint
  • cargo lint-all (not run: this machine does not have protoc)
  • cargo test -p wingfoil --all-features (not run: all features require protoc)
  • New behaviour is covered by a test asserting values and tick times (not applicable to the shutdown lifecycle)
  • cargo test -p wingfoil --lib --features bench (85 passed)
  • cargo clippy -p wingfoil --lib --features bench -- -D warnings
  • git diff --check

Notes for the reviewer

The focused regression test asserts that stop consumes the live worker handle, waits for its exit, and leaves the signal as Kill rather than letting the old error path overwrite it with End.

Disclosure: OpenAI Codex assisted with implementation and tests. The exact patch was independently reviewed by Grok and validated locally; no AI model is credited as a legal author.

Keep benchmark teardown deterministic by retaining and joining the worker handle while treating the intentional kill signal as a clean exit.
@0-jake-0
0-jake-0 merged commit f56b13f into wingfoil-io:main Aug 15, 2026
7 checks passed

Copy link
Copy Markdown
Contributor

Merged — thank you, @snowyukitty. Nice diagnosis: treating the Kill-driven exit as expected is the part that makes this more than a mechanical join(), and it removes a genuinely misleading error log from every benchmark teardown. The &self → &mut self change lands cleanly too, since add_bench already goes through borrow_mut().

One follow-up, opened as #847, and it's a gap in the test rather than in your fix. stop_joins_worker_and_treats_kill_as_clean_shutdown asserts worker.is_none() and that the signal stayed Kill — but both of those hold as soon as the handle is taken, joined or not. Checked by mutation on the merged commit:

Mutation Test result
Remove the Kill early-return FAILS (guarded — your half works)
Replace the join with let _ = self.worker.take(); PASSES (unguarded)

#847 adds assert_eq!(Arc::strong_count(&bencher.signal), 1): the worker's own clones of signal drop with its stack, so the caller holding the last reference is only observable once the thread has genuinely finished. Passes 5/5 with the join, fails 8/8 without.

Also noted there and deliberately left out: Bencher still has no Drop, so a criterion panic between start() and stop() leaves the ALWAYS-activated worker spinning a core. Pre-existing, not something #845 introduced.


Generated by Claude Code

0-jake-0 added a commit that referenced this pull request Aug 15, 2026
`stop_joins_worker_and_treats_kill_as_clean_shutdown` guarded the `Kill`
half of #845 but not the join it is named for: replacing the join with a
bare `self.worker.take()` left the test passing, because taking the handle
already satisfies both of its assertions.

Assert `Arc::strong_count(&bencher.signal) == 1` instead. The worker holds
its own clones of `signal` (the trigger's and the sink's), which drop with
its stack, so the caller owning the last reference is observable only once
the thread has actually finished.

Verified by mutation: passes with the join, fails without it.


Claude-Session: https://claude.ai/code/session_016uTUQ2a6B1Hscropr8rvt6

Co-authored-by: Claude <[email protected]>
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.

bencher: ERROR logged on every clean stop; worker thread never joined; pointless Arc clone

2 participants