fix: delay watcher unignore to prevent echo push-back loop#7
Merged
Conversation
When the CLI receives a sync event from the server and writes/deletes a file locally, the watchdog inotify event is queued by the kernel and delivered asynchronously. By the time the observer thread processes it, unignore_file had already been called, causing the watcher to treat the server-written file as a local change and push it back — creating an echo loop confirmed in logs (NoteSyncModify received → NoteModify sent back → server pushes again). Fix: add asyncio.sleep(0.6) before unignore_file in all server→client file operation handlers (write, delete, rename, chunked download) in both NoteSync and FileSync. This keeps the file ignored until the watchdog debounce window (0.5s) has expired.
Reviewer's guide (collapsed on small PRs)Reviewer's GuideAdds a small async delay before releasing filesystem ignore locks for server-initiated sync operations to avoid the watchdog treating server writes/deletes/renames as local changes and echoing them back to the server. Sequence diagram for server-initiated file change handling with delayed unignoresequenceDiagram
actor User
participant WSServer
participant CLISync
participant IgnoreManager
participant Watchdog
rect rgb(245,245,245)
User->>WSServer: Edit note/file
WSServer->>CLISync: NoteSyncModify / FileSyncUpdate
end
rect rgb(230,255,230)
Note over CLISync: After fix (with delay)
CLISync->>IgnoreManager: ignore_file(rel_path)
CLISync->>CLISync: Apply server change
CLISync-->>Watchdog: Filesystem write/delete/rename
Watchdog-->>IgnoreManager: Check ignore status
IgnoreManager-->>Watchdog: Path ignored
Watchdog--xCLISync: No local event dispatched
CLISync->>CLISync: await asyncio.sleep(0.6)
CLISync->>IgnoreManager: unignore_file(rel_path)
end
rect rgb(255,230,230)
Note over CLISync: Before fix (no delay)
CLISync->>IgnoreManager: ignore_file(rel_path)
CLISync->>CLISync: Apply server change
CLISync->>IgnoreManager: unignore_file(rel_path)
CLISync-->>Watchdog: Filesystem write/delete/rename
Watchdog-->>IgnoreManager: Check ignore status
IgnoreManager-->>Watchdog: Path not ignored
Watchdog-->>CLISync: Local modify/delete event
CLISync->>WSServer: NoteModify / FileSyncUpdate (echo)
WSServer->>CLISync: Re-sends change (loop)
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The hard-coded
await asyncio.sleep(0.6)is a bit of a magic number; consider centralizing this debounce duration in a clearly named constant or configuration so its intent is clear and easier to tune across all handlers. - Since the sleep is happening inside
finally, these handlers will now always incur at least 0.6s of extra runtime even on errors; consider whether you want to skip or shorten the delay on failure cases, or make the delay conditional on successful local application.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The hard-coded `await asyncio.sleep(0.6)` is a bit of a magic number; consider centralizing this debounce duration in a clearly named constant or configuration so its intent is clear and easier to tune across all handlers.
- Since the sleep is happening inside `finally`, these handlers will now always incur at least 0.6s of extra runtime even on errors; consider whether you want to skip or shorten the delay on failure cases, or make the delay conditional on successful local application.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Closed
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.
Problem
When the CLI receives a
NoteSyncModify/FileSyncUpdate/FileSyncDeletefrom the server and applies it locally, the watchdog's inotify event is delivered asynchronously by the kernel. By the time the observer thread processes the event,unignore_filehad already been called — causing the watcher to treat the server-written file as a local change and push it straight back to the server.Confirmed in logs:
Fix
Add
await asyncio.sleep(0.6)beforeunignore_filein all server→client file operation handlers. This holds the ignore lock past the watchdog debounce window (0.5 s), so any inotify events from the server-side write/delete/rename are suppressed before the lock is released.Affected handlers (5 total):
NoteSync._on_sync_modifyNoteSync._on_sync_deleteFileSync._on_sync_updateFileSync._on_sync_deleteFileSync._on_sync_renameFileSync._finalize_downloadSummary by Sourcery
Delay unignoring files after applying server-initiated sync operations to avoid echoing those changes back to the server.
Bug Fixes:
Enhancements: