Resume file watching automatically after restart - #23
Conversation
- Persist the watched folder to the Tauri Store when watching starts and clear it when the user explicitly stops watching - On launch, restore the saved folder and restart the watcher in the background; the initial scan re-checks files against the server so changes made while the app was closed are synced too - Persist upload config (ignored patterns, delays, etc.) so the resumed watcher runs with the user's saved settings instead of defaults; the server URL always comes from the build env, never the store - Add get_watched_folder command and a watch_resumed event so the UI reflects a resumed watch regardless of load order - Register tauri-plugin-single-instance (release builds only) so a second launch focuses the existing window instead of spawning a duplicate watcher that would double-upload every change Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Claude finished @cohogan's task in 2m 56s —— View job Code Review: Resume file watching after restart
Overall this is a well-structured PR. The refactor of Bug: Frontend shows folder as watched when resume fails
During resume, the code eagerly sets The Suggested fix: Either (a) don't set Option (b) is probably better UX since it lets you show a transient "Resuming…" state: // On failure inside the spawn_blocking:
Err(e) => {
log::error!("Failed to resume watching {folder}: {e}");
*watched_folder_state.lock() = None;
let _ = app_handle.emit("watch_resume_failed", &folder); // <-- new
}// In simple.tsx
const unlistenWatchResumeFailed = listen("watch_resume_failed", () => {
setSelectedFolder("");
});Nit: Redundant store write on resume path
Observation:
|
- Emit watch_resume_failed so the UI clears the watched folder and shows an error toast instead of displaying a folder that is not being watched - Log upload-config serialization failures instead of silently persisting null Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Addressed the review in 37f4e1e:
🤖 Generated with Claude Code |
|
Claude finished @cohogan's task in 2m 30s —— View job
Code Review: Resume file watching after restart (post-fix)The fixes from the first review (commit 37f4e1e) look correct — Issue:
|
serde(default) on UploadConfig prevents a version upgrade that adds a config field from failing deserialization and silently resetting the user's saved settings to defaults. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Applied the On the resume-vs-user-start race: agreed it's a design note rather than a bug. The window is a few seconds at launch, the mutex keeps final state consistent, and the worst case is a few spurious queue entries from the losing scan (which the server-side CRC dedup absorbs). A generation counter can be added if it ever shows up in practice. 🤖 Generated with Claude Code |
|
Claude finished @cohogan's task in 2m 23s —— View job
Code Review: Resume file watching after restart (round 3)Previous review rounds caught and fixed the main issues (UI desync on resume failure, silent Issue:
|
Consistent with the explicit error handling on the write side: a corrupted or wrong-typed stored config now leaves a warning in the log before falling back to defaults. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Applied the restore-side logging fix in the latest commit — a corrupted stored config now logs a warning before falling back to defaults, matching the write side. The stop-during-resume race remains a known narrow window as discussed; a generation counter is the right fix if it ever surfaces in practice. 🤖 Generated with Claude Code |
|
Claude finished @cohogan's task in 2m 6s —— View job
Code Review: Resume file watching after restart (round 4)The three prior review rounds caught the main issues (UI desync on resume failure, silent Issue:
|
A watch start whose initial scan is still running (potentially tens of seconds on large folders) could finish after the user hit Stop or picked a different folder, silently re-installing the watcher and re-persisting the store key. A generation counter now invalidates in-flight starts: every start/stop bumps it, and the final install step checks it under the watcher lock before committing watcher, in-memory state, and store. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Took the round-4 race seriously and went one step further than the suggested Instead, a
Re-verified the happy path end-to-end on Windows (seeded store → headless launch → 🤖 Generated with Claude Code |
|
Claude finished @cohogan's task in 4m 57s —— View job
Code Review: Resume file watching after restart (round 5)All four prior review rounds' fixes are correctly applied and verified. The Observation: Superseded scan still queues files for upload
The generation check happens after // Scan runs fully — no generation check here
capture_initial_contents(&folder_path, app_handle, upload_queue, upload_config)?;
// ... create watcher ...
// Generation check only happens here, after the scan
{
let mut watcher_guard = watcher_state.lock();
if generation.load(Ordering::SeqCst) != expected_generation {
return Ok(WatchStartOutcome::Superseded); // scan's queue entries persist
}
}This is consistent with pre-existing behavior ( A future improvement could periodically check the generation during the scan (e.g., every N files) to bail out early, but that adds complexity for marginal benefit. Pre-existing:
|
|
Acknowledging the two round-5 observations without further changes:
All actionable findings from rounds 1–4 are applied and verified. Ready for merge. 🤖 Generated with Claude Code |
Summary
With autostart enabled (added in #22), the app now launches at login — but it forgot what it was doing before the restart. This PR makes sync continue across restarts with no user interaction:
watched_folderkey) whenever watching starts; cleared only when the user explicitly hits Stop.setup()restores the saved folder and restarts the watcher on a background thread. The existing initial-scan path re-checks every file against the server (CRC32C dedup), so files that changed while the app was closed get synced too — unchanged files are skipped server-side.upload_configand restored at startup. The server URL is deliberately always taken from the build env rather than the store, so a config written by a dev build can never point a production build at localhost.get_watched_foldercommand +watch_resumedevent, so the frontend shows the watched folder whether the webview loads before or after the resume finishes.tauri-plugin-single-instancenow focuses the existing window instead. Gated out of debug builds sopnpm tauri devstill works alongside the installed app.Testing
Verified end-to-end on Windows with a debug build against the production backend:
watched_folderin the store, launched the app with no UI interaction → log showsResumed watching <folder> after restart, the initial scan queued and uploaded the folder's file, and heartbeat continued.cargo check,cargo clippy, andtscall clean.🤖 Generated with Claude Code