Fix watcher degradation on watch exhaustion and prolonged lock contention#877
Closed
thismilktea wants to merge 3 commits into
Closed
Fix watcher degradation on watch exhaustion and prolonged lock contention#877thismilktea wants to merge 3 commits into
thismilktea wants to merge 3 commits into
Conversation
colbymchenry
added a commit
that referenced
this pull request
Jun 15, 2026
…contention (#891) The live file watcher could stay "alive" after it had stopped being trustworthy. EMFILE/ENFILE watch-resource exhaustion only logged (and was silently tolerated on the Linux per-directory path), and prolonged LockUnavailableError retried forever at the normal debounce cadence — both left auto-sync dead while the index silently drifted stale. Especially bad for long-running MCP/daemon sessions. Add a one-way degrade(): on watch-resource exhaustion (any watch strategy) or on lock contention past a bounded exponential-backoff budget, log once, fire a new onDegraded callback, and stop. start() now returns false consistently when the per-directory path degrades at startup — it previously returned true on Linux, so the MCP server reported the watcher "active" when it had degraded. Wire onDegraded into the MCP server so callers are actually told, and expose isDegraded()/getDegradedReason(). Builds on the approach in #877 by @thismilktea. Validated on macOS (recursive), Linux (per-directory, Docker) and Windows (recursive) — 30/30 watcher + watch-policy tests on each. Closes #876 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
|
Thanks for this, @thismilktea — solid diagnosis and the degrade/backoff approach was the right one. I've merged it into Two things I adjusted on top of your branch:
Also validated the recursive path on Windows (Parallels) in addition to macOS/Linux. Closing in favor of #891 — thanks again for driving this. 🙏 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #876
Summary
This PR hardens the live file watcher around two reliability failure modes:
The goal is to fail closed and clearly once live watching is no longer trustworthy, while preserving the current behavior for normal edits and short-lived contention.
What changed
Watch exhaustion
onDegradedcallback so callers can observe permanent watcher degradationLock contention
LockUnavailableErrorInternal cleanup
err.codeis availableWhy
Before this change, the watcher could remain "alive" after it had effectively stopped being trustworthy:
This is especially problematic for long-running MCP/daemon sessions.
Tests
Added / extended watcher tests for:
LockUnavailableErrordegradationVerified with: