You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On node shutdown, tearing down zenoh state (Subscriber / Publisher / Sessionundeclare) blocks when the zenoh net runtime is wedged — e.g. stuck retrying an unreachable scouted peer. Today we only bound that hang with a timeout (ZENOH_TEARDOWN_TIMEOUT, added in #2439); we never fix the wedge itself. This issue tracks eliminating the wedge at its source so teardown completes promptly instead of being abandoned.
This is the defense-in-depth follow-up to the #2742 nightly regression. The immediate fix there lowers the teardown deadline below the daemon's force-kill grace so a wedged node exits cleanly rather than being force-killed (ExitCode(1) on Windows). That makes the symptom benign but leaves the wedge — and a leaked undeclare — in place.
Background
teardown_with_timeout runs the zenoh drop on a helper thread and blocks the main thread up to ZENOH_TEARDOWN_TIMEOUT (apis/rust/node/src/node/mod.rs), used by both DoraNode::drop and EventStream::drop.
The teardown blocks because Subscriber/Publisher/LivelinessToken/Session teardown does a synchronous undeclare on the shared session, which does not return while zenoh's net runtime is busy (scouting / retrying peers it can't reach). See the EventStream::drop comment (apis/rust/node/src/event_stream/mod.rs) and Nightly regression since 2026-06-30 #2425.
On headless CI runners there is no multicast and scouted peers are typically unreachable, which is exactly the condition that wedges the net runtime.
Why the timeout isn't enough
When the deadline fires we log a warning, abandon the (detached) teardown thread, and continue shutdown. That means:
the undeclare never happens → the subscription/liveliness token is leaked on the session until the process exits;
every shutdown under a partition pays up to the full deadline of latency;
the leaked detached thread is only reclaimed by process exit.
Fine as a safety net, wrong as the steady state.
Proposed directions (to investigate)
Bound scouting / connect at the zenoh layer. Configure the session so the net runtime doesn't sit in an unbounded retry loop that blocks undeclare — e.g. tighter scouting/connect timeouts, or disable multicast scouting where we already know endpoints (cf. the dev-container workaround that sets explicit endpoints + exit_on_failure: false). Goal: undeclare returns promptly even with no reachable peers.
Make teardown non-blocking by construction. If a clean undeclare can't be guaranteed to return quickly, undeclare best-effort / fire-and-forget so node Drop never blocks on the net runtime, rather than relying on a wall-clock deadline.
Root-cause the zenoh undeclare block itself and, if it's a zenoh bug, file upstream / bump the pin.
Acceptance
A node whose zenoh session has only unreachable scouted peers tears down its subscribers/publishers/session in well under the current deadline (target: sub-second), with no leaked undeclare.
No dependence on ZENOH_TEARDOWN_TIMEOUT firing during a normal partitioned shutdown (the timeout stays only as a last-resort backstop).
Summary
On node shutdown, tearing down zenoh state (
Subscriber/Publisher/Sessionundeclare) blocks when the zenoh net runtime is wedged — e.g. stuck retrying an unreachable scouted peer. Today we only bound that hang with a timeout (ZENOH_TEARDOWN_TIMEOUT, added in #2439); we never fix the wedge itself. This issue tracks eliminating the wedge at its source so teardown completes promptly instead of being abandoned.This is the defense-in-depth follow-up to the #2742 nightly regression. The immediate fix there lowers the teardown deadline below the daemon's force-kill grace so a wedged node exits cleanly rather than being force-killed (
ExitCode(1)on Windows). That makes the symptom benign but leaves the wedge — and a leakedundeclare— in place.Background
teardown_with_timeoutruns the zenoh drop on a helper thread and blocks the main thread up toZENOH_TEARDOWN_TIMEOUT(apis/rust/node/src/node/mod.rs), used by bothDoraNode::dropandEventStream::drop.Subscriber/Publisher/LivelinessToken/Sessionteardown does a synchronousundeclareon the shared session, which does not return while zenoh's net runtime is busy (scouting / retrying peers it can't reach). See theEventStream::dropcomment (apis/rust/node/src/event_stream/mod.rs) and Nightly regression since 2026-06-30 #2425.@schemaAdvancedSubscribers / publishers on the same shared session, widening the surface that can wedge this way.Why the timeout isn't enough
When the deadline fires we log a warning, abandon the (detached) teardown thread, and continue shutdown. That means:
undeclarenever happens → the subscription/liveliness token is leaked on the session until the process exits;Fine as a safety net, wrong as the steady state.
Proposed directions (to investigate)
undeclare— e.g. tighterscouting/connecttimeouts, or disable multicast scouting where we already know endpoints (cf. the dev-container workaround that sets explicit endpoints +exit_on_failure: false). Goal:undeclarereturns promptly even with no reachable peers.undeclarecan't be guaranteed to return quickly, undeclare best-effort / fire-and-forget so nodeDropnever blocks on the net runtime, rather than relying on a wall-clock deadline.undeclareblock itself and, if it's a zenoh bug, file upstream / bump the pin.Acceptance
undeclare.ZENOH_TEARDOWN_TIMEOUTfiring during a normal partitioned shutdown (the timeout stays only as a last-resort backstop).References
@schemasub/pub surface)apis/rust/node/src/node/mod.rs—ZENOH_TEARDOWN_TIMEOUT,teardown_with_timeout,DoraNode::dropapis/rust/node/src/event_stream/mod.rs—EventStream::drop