feat(watchers): Improve Node watcher robustness: file-level inode tracking, abortable restarts, restart race guards, and untracked-file handling

This commit is contained in:
2025-12-10 14:18:40 +00:00
parent 8677f61da1
commit 5dda689b4c
4 changed files with 168 additions and 44 deletions

View File

@@ -79,11 +79,13 @@ The Node.js watcher includes automatic recovery mechanisms based on learnings fr
- Watchers automatically restart when errors occur
- Exponential backoff (1s → 30s max)
- Maximum 3 retry attempts before giving up
- **v6.2.0+**: Race condition guards prevent orphan watchers when `stop()` is called during restart
**Inode tracking (critical for long-running watchers):**
- `fs.watch()` watches the **inode**, not the path!
- When directories are replaced (git checkout, atomic saves), the inode changes
- Health check detects inode changes and restarts the watcher
- **v6.2.0+**: File-level inode tracking detects delete+recreate (common editor save pattern)
- This is the most common cause of "watcher stops working after some time"
**Health check monitoring:**
@@ -91,6 +93,7 @@ The Node.js watcher includes automatic recovery mechanisms based on learnings fr
- Detects when watched paths disappear
- Detects inode changes (directory replacement)
- Detects ENOSPC errors (inotify limit exceeded)
- **v6.2.0+**: Protected against dual-restart race conditions (health check + error handler)
**ENOSPC detection (Linux inotify limit):**
- Detects when `/proc/sys/fs/inotify/max_user_watches` is exceeded
@@ -100,6 +103,10 @@ The Node.js watcher includes automatic recovery mechanisms based on learnings fr
- Subscriber errors don't crash the watcher
- All events emitted via `safeEmit()` with try-catch
**Untracked file handling (v6.2.0+):**
- Files created after initial scan are properly detected
- Untracked file deletions emit `unlink` events instead of being silently dropped
**Verbose logging:**
- All lifecycle events logged with `[smartwatch]` prefix
- Helps debug watcher issues in production
@@ -113,6 +120,7 @@ Example log output:
[smartwatch] Health check: 1 watchers active
[smartwatch] Inode changed for ./src: 12345 -> 67890
[smartwatch] fs.watch watches inode, not path - restarting watcher
[smartwatch] File inode changed (delete+recreate): ./src/file.ts
```
### Known fs.watch Limitations