Skip to content

feat(event): add AutoResetEvent - #310

Merged
tisonkun merged 8 commits into
apache:mainfrom
tisonkun:codex/auto-reset-event
Sep 14, 2026
Merged

tisonkun merged 8 commits into
apache:mainfrom
tisonkun:codex/auto-reset-event

Conversation

@tisonkun

@tisonkun tisonkun commented Sep 14, 2026

Copy link
Copy Markdown
Member

Summary

Add event::AutoResetEvent for coalescing notifications to one waiter under the existing event feature. Both event types expose is_set for non-consuming state inspection and try_wait for an immediate wait: ManualResetEvent stays set on success, while AutoResetEvent consumes a stored signal.

Keep the types in separate modules with matching method order and documentation. Examples demonstrate migrations from Tokio Notify for a cache worker and index-revision readers, plus a worker that coalesces requests across multiple rebuilds. Downstream draft scopedb/cache2#52 replaces watch<()> drain notifications and pins the event implementation by Git revision for CI.

Design Notes

Each auto-reset set assigns a signal to a registered wait or retains one unassigned signal. Assigned signals belong to their waits until completion or cancellation; cancellation transfers or restores the signal. reset clears only an unassigned signal, is_set observes only that stored state, and try_wait cannot take another wait's assigned signal. Reuse the internal mutex and waiter list, keeping wakes and waker destruction outside the lock.

Validation: cargo x test, cargo x lint, and the coalesced_worker, notify_vs_event, and once_cell_vs_lazy_cell examples passed. Event tests cover non-consuming inspection, immediate waits, reset, cancellation handoff, waker lifecycle, wake panics, and publication races.

Closes #292.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The concurrency-sensitive synchronization changes warrant final human review, with documentation reflow nits remaining.

Pull request overview

Adds event::AutoResetEvent, a coalescing, cancellation-safe notification primitive for one waiter.

Changes:

  • Implements FIFO signaling, cancellation handoff, owned waits, and synchronization semantics.
  • Adds behavioral, concurrency, trait, and panic-safety tests.
  • Updates documentation, API maps, changelog, and adds a worker example.
File summaries
File Summary
tests-integration/tests/traits_test.rs Adds trait coverage.
tests-integration/tests/auto_reset_event_test.rs Tests event behavior and concurrency.
README.md Updates the API map.
examples/src/coalesced_worker.rs Adds a coalesced worker example.
examples/Cargo.toml Registers the example and feature.
CHANGELOG.md Records the new feature.
asyncband/src/lib.rs Updates crate API documentation.
asyncband/src/event/mod.rs Documents and exports the event.
asyncband/src/event/auto_reset.rs Implements AutoResetEvent.
Review details

Suppressed comments (14)

asyncband/src/event/auto_reset.rs:40

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
/// Waiting consumes a signal without returning it on completion. Unlike a
/// [`ManualResetEvent`](super::ManualResetEvent), this event does not release all observers of a
/// condition. Unlike a semaphore, it does not count unused signals or return a permit guard.

asyncband/src/event/auto_reset.rs:48

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
/// Memory operations sequenced before a `set` are visible after a wait or
/// [`try_wait`](Self::try_wait) consumes its signal. This includes sets coalesced into a stored
/// signal and signals passed on after cancellation. The event carries no application state: when it
/// is used to notify changes to an external predicate, callers must synchronize access to that
/// predicate separately.

asyncband/src/event/auto_reset.rs:36

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
/// Each [`set`](Self::set) assigns a signal to the oldest registered wait, or stores one signal
/// if no wait is queued. Repeated sets coalesce only while an unassigned signal is stored. A
/// signal assigned to a wait belongs to that wait until it completes or is cancelled; subsequent
/// sets can release other waits even before previously selected waits are polled again.

asyncband/src/event/auto_reset.rs:89

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
    /// A stored signal is available to a future wait. Further sets coalesce while it remains
    /// unassigned. Creating a wait future does not register it; registration happens when it is
    /// first polled without a stored signal.

asyncband/src/event/auto_reset.rs:94

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
    /// Panics if waking the selected task panics. Its signal remains assigned and can still be
    /// consumed by polling that wait or passed on by dropping it.

asyncband/src/event/auto_reset.rs:105

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
    /// This never takes a signal assigned to another wait or bypasses a queued wait. A `false`
    /// result is only a snapshot; use [`wait`](Self::wait) to wait for a future signal.

asyncband/src/event/auto_reset.rs:122

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
    /// The first poll consumes a stored signal immediately, or joins the FIFO waiter queue.
    /// Merely creating this future neither reserves a signal nor establishes a queue position.
    /// Signals assigned to other waits cannot be consumed by this wait.

asyncband/src/event/auto_reset.rs:129

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
    /// Dropping this future before it returns `Ready` removes its registration. If a signal was
    /// assigned to it, that signal is passed to the oldest queued wait or stored for a future
    /// wait, coalescing with any signal already stored. Retrying a cancelled wait joins the back
    /// of the queue. Dropping a completed wait does not return its consumed signal.

asyncband/src/event/auto_reset.rs:141

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
    /// The future owns the [`Arc`], making it suitable for spawned tasks. Its registration,
    /// fairness, and cancellation semantics match [`wait`](Self::wait).

asyncband/src/event/mod.rs:22

  • These newly added Markdown paragraphs are wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow this paragraph before merging.
//! A [`ManualResetEvent`] releases all registered waits and remains ready until explicitly reset.
//! An [`AutoResetEvent`] releases one wait per assigned signal and consumes that signal when the
//! wait completes. With no queued waits, it retains at most one signal, coalescing further sets.

asyncband/src/event/mod.rs:26

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
//! Both types retain state, unlike a condition variable's unbuffered notifications. Use a
//! semaphore when unused permits must accumulate, or a watch channel when each receiver needs to
//! observe state changes independently.

asyncband/src/event/mod.rs:46

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
//! An auto-reset event is useful for a single worker that rechecks external state after a signal.
//! Publish the state before calling `set`, and check the predicate in a loop. A signal arriving
//! between the predicate check and the first poll is retained, so the worker does not miss it.
//! A leftover signal can cause an extra predicate check without implying new work.

asyncband/src/event/mod.rs:50

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
//! Multiple waits on an auto-reset event compete for signals. This does not broadcast a predicate
//! change to every observer, and the simple check-then-wait loop is not a general multi-consumer
//! queue protocol: several changes can coalesce before those consumers register their waits.

examples/src/coalesced_worker.rs:21

  • This newly added Markdown paragraph is wrapped across source lines, but the repository documentation convention in AGENTS.md:42-44 requires each prose paragraph to occupy one source line. Please reflow it before merging.
//! One worker rebuilds a snapshot of the latest requested revision. Intermediate revisions may
//! coalesce: this is not a queue of jobs that must each run, or a broadcast to multiple observers.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@tisonkun
tisonkun merged commit ad239dc into apache:main Sep 14, 2026
9 checks passed
@tisonkun
tisonkun deleted the codex/auto-reset-event branch September 14, 2026 15:43
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.

Provide an auto-reset event

2 participants