Skip to content

fix(server): stop Linux watcher event storms on busy working trees#794

Merged
boudra merged 1 commit intogetpaseo:mainfrom
312223105:fix/linux-watcher-storm
May 7, 2026
Merged

fix(server): stop Linux watcher event storms on busy working trees#794
boudra merged 1 commit intogetpaseo:mainfrom
312223105:fix/linux-watcher-storm

Conversation

@312223105
Copy link
Copy Markdown
Contributor

@312223105 312223105 commented May 7, 2026

Fixes #795

Summary

  • Linux fs.watch isn't recursive, so the working-tree watcher walks the whole subtree and registers a per-directory watcher; every inotify event then re-scans the tree and rebuilds watchers. A continuously-written subtree pegs the event loop at 100% CPU and stalls the websocket.
  • Skip git-ignored directories when walking — load git ls-files -o -i --directory --exclude-standard once per root with a 5 min cache.
  • Cap the walked directory count at 5000 so a misconfigured repo can't blow past the inotify budget.
  • Add a 2s cooldown between refresh passes so an event flurry collapses into one re-scan instead of a tight do/while loop.

Test plan

  • npx vitest run src/server/workspace-git-service.test.ts --bail=1 — 17/17
  • npm run typecheck / npm run lint / npm run format (pre-commit hook)
  • Daemon repro: 100% CPU / 5006 inotify watches / websocket unresponsive → ~5% CPU / 263 watches / reachable, all agents idle

On Linux fs.watch isn't recursive, so each working tree manually walks
the entire subtree and registers a per-directory watcher. Every inotify
event then re-scans the tree and rebuilds watchers. A working tree
containing a directory that's continuously written (e.g. test-runtime
data, build artefacts) drives the event loop to 100% CPU and the
daemon stops responding on its websocket.

Skip git-ignored directories when walking — load `git ls-files -o -i
--directory --exclude-standard` once per root (5 min cache) and skip
its entries. Cap the walked directory count at 5000 so a misconfigured
repo can't blow past the inotify budget. Add a 2s cooldown between
refresh passes so a flurry of events collapses into one re-scan
instead of a tight loop.
@312223105 312223105 force-pushed the fix/linux-watcher-storm branch from 40063a1 to 6b15351 Compare May 7, 2026 08:04
@boudra boudra merged commit 4fa1db8 into getpaseo:main May 7, 2026
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.

Daemon pegs at 100% CPU on Linux when a working tree contains a frequently-written gitignored subtree

2 participants