Skip to content

bug: v0.2.1 — upgrade cleanup, online-file races, instant exit#47

Merged
Gumbees merged 1 commit into
developmentfrom
bug/v0.2.1-upgrade-and-online-races
May 26, 2026
Merged

bug: v0.2.1 — upgrade cleanup, online-file races, instant exit#47
Gumbees merged 1 commit into
developmentfrom
bug/v0.2.1-upgrade-and-online-races

Conversation

@Gumbees

@Gumbees Gumbees commented May 26, 2026

Copy link
Copy Markdown
Collaborator

Three upgrade/lifecycle bugs in one patch. Cargo bumped to 0.2.1.

1. Manual upgrade from 0.1.x left leftovers + could deadlock migration

The in-app updater rename-dances on the installed binary, but a user who downloads the new release manually from GitHub Releases (or upgrades across the 0.2.0 install-layout change) ran into:

  • Old binary still on disk at %APPDATA%\ImmichSync\ or %APPDATA%\bees-roadhouse\immichsync\.
  • Stale HKCU\...\Run\ImmichSync autostart entry pointing at the old path → both 0.1.x and 0.2.x launch at next login.
  • Stale Apps & Features Uninstall key still pointing at the old install dir.
  • Worst: if v0.1.x was still running, migrate_to_split_layout tried to rename an open state.db → silently fell back to copy → remove_file failed → divergent DBs at old + new paths.

Adds cleanup_legacy_install() (called from main() before the migrations) that:

  • Detects legacy binaries at both known 0.1.x paths.
  • taskkill /F /FI 'PID ne <ours>' /IM immichsync.exe to release file locks.
  • Removes the legacy binary + version.txt.
  • Clears the Run / Uninstall registry entries only when their value points at a legacy path (users with autostart disabled stay disabled).

2. SHA-1 hash + upload-stream hydrated cloud placeholders

The watcher's filter drops cloud-placeholder files at discovery, but a file can be evicted between watcher → queue or queue → worker (OneDrive / SeaDrive auto-evict under storage pressure). Reading the placeholder triggered a full cloud download — gigabytes of bandwidth + CPU for a file we were about to skip anyway.

The comment at queue.rs:233-237 explicitly relied on the watcher's filter being authoritative; it's not, race-wise.

  • queue.rs:process_file: is_online_file(&meta) re-check between fs::metadata and hash_file. Skips with Ok(None).
  • worker.rs:process_item: is_online_file re-check after pickup, before opening the file for upload. Marks the entry "failed" with a recognizable message; the watcher's reconciliation re-enqueues when the file is local again.

3. Tray Quit / WM_QUIT waited up to 3s

pipeline.stop() graceful path awaits the spawned per-item upload tasks (up to 3s). On user-initiated Quit that's a noticeable hang — "forget the current operation, drop it, exit."

Adds App::shutdown_and_exit() -> !:

  • Stops the watch engine (releases file handles, fast).
  • pipeline.signal_stop() — signals the worker but doesn't wait.
  • std::process::exit(0).

In-flight `"uploading"` rows are recovered by `reset_stale_uploading` on next launch (existing mechanism), so partial uploads retry cleanly. The graceful shutdown() path is preserved for the RestartToUpdate flow (the new instance needs a clean handoff of state.db).

Test plan

  • `cargo test` — 110 tests passing locally (added 5 new)
  • `cargo clippy --all-targets -- -D warnings` clean
  • `cargo fmt --all -- --check` clean
  • Manual: install v0.1.8, then launch a v0.2.1 binary from Downloads. Verify legacy binary + Run entry + Uninstall key are gone after first launch.
  • Manual: SeaDrive evict a tracked file mid-queue, verify worker skips it without hydrating.
  • Manual: click tray Quit while an upload is in-flight, verify tray disappears instantly.

Three bugs fixed in one patch:

1. Manual upgrade from 0.1.x left the old binary, autostart entry, and
   Apps & Features Uninstall key in place, and could deadlock the
   state.db migration when a v0.1.x process was still running. Adds
   cleanup_legacy_install() that runs before migrations: kills other
   immichsync.exe instances, removes legacy binaries at
   %APPDATA%\ImmichSync and %APPDATA%\bees-roadhouse\immichsync, and
   clears stale Run / Uninstall registry entries when they point at
   a legacy path.

2. SHA-1 hash and upload-stream code paths trusted the watcher's
   placeholder filter, but a file can be evicted to the cloud after
   the watcher sees it and before queue/worker reads it. Reading the
   placeholder hydrates the whole file from the cloud — pages of
   bandwidth and CPU for a file the watcher would skip on its next
   pass. Adds is_online_file re-checks at queue-time (in process_file
   between metadata fetch and hash) and worker-time (in process_item
   before opening the file). Worker marks the entry "failed" with a
   descriptive message; the watcher's reconciliation re-enqueues when
   the file becomes local again.

3. Tray Quit and WM_QUIT waited up to 3s on pipeline.stop()'s graceful
   shutdown of in-flight uploads, making the tray feel laggy on exit.
   Adds shutdown_and_exit() — signals the watch engine + upload worker
   to stop, then process::exit(0). In-flight "uploading" rows are
   already reset to "pending" by reset_stale_uploading on next launch,
   so nothing is lost.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Gumbees Gumbees merged commit 5828c91 into development May 26, 2026
2 checks passed
@Gumbees Gumbees deleted the bug/v0.2.1-upgrade-and-online-races branch May 26, 2026 01:07
@Gumbees Gumbees mentioned this pull request May 26, 2026
4 tasks
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.

1 participant