chore: document WebUIHandler thread-safety#297
Conversation
210df33 to
df6cbf0
Compare
WebUIHandler is auto-derived Send + Sync (its only field is a function pointer plugin factory), and the existing doc comment already says "plugin instances are created per-render ... allowing concurrent renders with &self". But neither the type-level docs nor the rust integration page state Send + Sync explicitly, so an adopter has to either read the field list and reason about it themselves, or try sharing one across threads and hope the compiler agrees. This PR: - Expands the doc comment on `WebUIHandler` with a "Thread safety" section that states `Send + Sync`, explains why (function-pointer factory + per-render local context), and shows the `Arc<WebUIHandler>` sharing pattern. - Adds a `Thread safety` section to `docs/guide/integrations/rust.md` with the same `Arc` example so adopters following the integration page don't have to read the rustdoc. - Adds a compile-time `assert_send_sync::<WebUIHandler>()` inside the existing `#[cfg(test)]` module. If a future field breaks Send or Sync, the build fails immediately and prompts an update to both the type and the docs. No behavior change; docs + one compile-time assertion.
df6cbf0 to
d4d6bb2
Compare
mohamedmansour
left a comment
There was a problem hiding this comment.
WebUIHandler is already thread-safe. Current code has handle(&self), creates a fresh per-render WebUIProcessContext, and creates plugin instances per render from a factory. Concurrent renders can run in parallel with no Mutex.
I see some issues, The added rustdoc says per-render state is created inside render, but the method is handle; there is no Self::render. You need to change [render](Self::render) to [handle](Self::handle).
Another issue DESIGN.md still contradicts the thread-safety contract. Update DESIGN.md to match current code: factory function field, with_plugin(factory: fn() -> Box<dyn HandlerPlugin>), and handle(&self, ...), plus the explicit Send+Sync/thread-safe contract.
PR should say “already thread-safe” and update the stale spec/incorrect rustdoc link before merging.
…ndler API Addresses review feedback on #297: - Rustdoc on `WebUIHandler` now links to `Self::handle` (the canonical documented entry point used in the integration page) instead of `Self::render`. Reframes 'is Send + Sync' as 'is already Send + Sync' to make clear this PR documents an existing property, not a new one. - Drops the broken private intra-doc link to `WebUIProcessContext` (the struct is private; rustdoc emitted a private_intra_doc_links warning). Replaced with plain code text. - DESIGN.md handler section updated to match current code: * `plugin: Option<Box<dyn HandlerPlugin>>` -> `plugin_factory: Option<fn() -> Box<dyn HandlerPlugin>>` * `with_plugin(plugin: Box<...>)` -> `with_plugin(factory: fn() -> Box<...>)` * `handle(&mut self, ...)` -> `handle(&self, ...)` * New 'Thread safety' subsection making the Send + Sync / Arc-without-Mutex contract explicit in the spec. - DESIGN.md partial/action/template free-function signatures updated to match `route_handler.rs` (they no longer take a handler argument, which was the same staleness that contradicted the thread-safety story by implying `&mut WebUIHandler` was required). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thanks for the review! Fixed in Rustdoc link ( While I was in the doc-comment I also dropped a broken intra-doc link: the original additions linked to DESIGN.md (Handler Implementation section)
I also fixed the Verified locally:
|
|
|
||
| The realistic pattern is "construct once, clone into many tasks": | ||
|
|
||
| ```rust |
There was a problem hiding this comment.
Why do we need an example for thread safety, the docs state thread safety, we don't need more doc bloat showcasing how we can run the handler N times
What
Three small additions stating that
WebUIHandlerisSend + Sync:crates/webui-handler/src/lib.rs- expand the doc comment onWebUIHandlerwith a "Thread safety" section explaining why it'sSend + Syncand theArc<WebUIHandler>pattern.docs/guide/integrations/rust.md- new "Thread safety" section showing the sameArcexample, so adopters following the integration page don't have to read the rustdoc.crates/webui-handler/src/lib.rs- compile-timeassert_send_sync::<WebUIHandler>()inside the existing#[cfg(test)]module to fail-fast if a future field breaks Send or Sync.Why
I'm wiring a
WebUIHandlerinto a Tokio/Axum-shaped request path in an embedded host. The first question is "can I store one of these inaxum::extract::Stateand serve concurrent requests from it, or do I need a per-task instance or a mutex?". Today, that question is answered only indirectly:&self" - which strongly impliesSend + Sync, but doesn't say so.WebUIHandlerhas a single private field (Option<fn() -> Box<dyn HandlerPlugin>>), so the auto-traits do hold - but an adopter can't see the field from the public API and has to either reason about it from the struct definition or try compiling and find out.Stating
Send + Syncexplicitly in both the rustdoc and the integration page removes that lookup. The static assertion keeps the docs honest if someone later adds aRefCell/Rcfield.How I tested
(passes - the
assert_send_syncblock compiles, confirmingWebUIHandler: Send + Synctoday.)Notes
users/janechu/document-webui-handler-thread-safetyper my host repo's agent-driven branch convention.