Expand description
Health tracking + retry policy for FsWatchPool. Split out of pool.rs
so the recovery bookkeeping (what’s degraded, which backend is active)
is testable independent of the notify/tokio wiring.
Structs§
- FsWatch
Health - Snapshot of the pool’s current health, for diagnostics (
muxlog, eventually a UI surface — not built here, see spec §6 non-goals). - Health
State 🔒
Enums§
- Watch
Backend - Which
notifybackend is actually driving watches right now.Pollingonly happens if the native backend failed to construct at all (rare — e.g. inotify unavailable) — seeSPEC_SHARED_FS_WATCHER_FRAMEWORK_2026_08_07.md§4 point 2. Once picked at pool construction, this doesn’t change for the pool’s lifetime; per-path failures are tracked indegraded_pathsinstead, independent of which backend is in use.
Constants§
- HEALTH_
SWEEP_ INTERVAL - How often the background sweep re-arms every currently-degraded
path, self-healing a watch that failed to establish (or a prior sweep
found dead) without needing a dedicated retry loop running forever.
Deliberately scoped to degraded targets only, not every subscribed
path — an earlier version of this sweep re-issued
watch()unconditionally on everything, every tick, to also catch a silently dead healthy-looking watch (inotify instance-limit churn, a watched directory deleted and recreated at a new inode, a flaky network mount). That cost more than it bought:notify7.0.0’s Windows backend leaks a File + Semaphore handle pair on every redundantwatch()call (no cleanup of the previous entry), and even with anunwatch()first to avoid the leak, the gap betweenunwatch()andwatch()drops event coverage for consumers with no reconciliation backstop of their own (config_watcher_fs,EditorFileWatcher,MediaFileWatcher). Seepool.rs’ssweep()anddocs/status/STATUS_FS_WATCH_SWEEP_HANDLE_LEAK_2026_08_22.mdfor the full history and the accepted trade-off (a truly silent death of an already-healthy watch is no longer self-healed by this sweep). - RETRY_
BACKOFF - Backoff schedule for retrying a failed
watch()call, per spec §4 point 1 — bounded at 3 attempts over ~4.2s total, not indefinite: a path that’s still failing after this moves intodegraded_pathsand is picked up by the periodic health sweep (pool.rs’sHEALTH_SWEEP_INTERVAL) instead of spinning a dedicated retry loop forever.