Skip to content

Send update download progress on a small throttled event - #1072

Merged
enaboapps merged 3 commits into
mainfrom
fix/1071-updater-progress
Oct 15, 2026
Merged

enaboapps merged 3 commits into
mainfrom
fix/1071-updater-progress

Conversation

@enaboapps

@enaboapps enaboapps commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1071

Summary

The download progress callback emitted the full AppState for every network chunk: two snapshots, diagnostics and telemetry observers, a tray set_text, and a full webview re-render. A ~155 MB installer meant thousands of these, which could freeze the app.

  • Counting: updater::ProgressCounter counts bytes in AtomicU64s outside the shared state mutex.
  • Event: a new update-progress event carries { downloadedBytes, totalBytes }.
  • Throttle: updater::ProgressThrottle (pure, injectable Instant) emits the first sample, then only when ≥250 ms have passed and the whole percent has changed (time alone when the total is unknown). The completing sample is always emitted once.
  • State emission: full publish_update / emit_state now happens only on transitions (downloading, ready, failed, cancelled). The final byte count and total go into AppState.updater at ready. UpdateView::add_progress is removed.
  • Tray: TrayController::sync skips set_text / set_enabled when the native menu already shows the value. Each value is recorded only after its setter succeeds, so a failed call is retried on the next sync.
  • Diagnostics: a downloading updater entry is recorded when a download starts.
  • Frontend: App (always mounted) calls useUpdateProgress once, giving a single api.onUpdateProgress listener. It passes the merged updater state to the UpdateBanner and, through SettingsView, to UpdatesSection, so opening Updates mid-download shows the latest sample. Stale samples are cleared when a download ends. The UI text is unchanged.

Validation

Latest head, Node 24.19.0, Rust 1.97.1, Windows 11:

  • npm run prediction-model: verified offline neural model and workers
  • npm run lint: pass
  • npm test: vitest 13 files / 299 tests passed; node tests 12/12 passed
  • npm run build: pass
  • cargo fmt --manifest-path src-tauri/Cargo.toml --check: pass
  • cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings: pass
  • cargo test --manifest-path src-tauri/Cargo.toml: 790 passed, 5 ignored; 7 passed in the integration suite

New tests:

  • Rust throttle tests: the interval gate, the whole-percent gate, the completion flush, an unknown total, and a bound on events for a simulated 155 MB download.
  • A fake-artifact download test checks the throttled events and the final count. The existing fake-artifact cancellation test still passes.
  • Event payload serialization.
  • Tray tests: unchanged values are skipped, and a value whose setter failed is retried.
  • Frontend tests:
    • the progress event updates the bar and the banner, and the ready state comes from AppState;
    • opening Updates mid-download shows the last sample, with a single listener;
    • a download that is cancelled or fails and is then retried starts at 0 before the first new sample.

🤖 Generated with Claude Code

Each network chunk of an update download locked the shared state and
emitted the whole AppState, running the diagnostics and telemetry
observers, resetting the tray text and re-rendering the webview. A large
installer meant thousands of these and could freeze the app.

Bytes are now counted atomically outside the state mutex and sent on an
update-progress event at most every 250 ms and only when the whole
percent changes, with the completing sample always sent. Full state is
emitted only for status transitions, with the final size at ready. The
tray skips mutations whose value has not changed, and a downloading
entry is recorded in the diagnostic history.

Closes #1071

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps enaboapps added this to the v1.0.0-rc.28 milestone Oct 15, 2026
@enaboapps enaboapps added the bug Something isn't working label Oct 15, 2026
The Updates tab mounted its own progress listener, so opening it during
a download showed zero until the next throttled sample. App now owns the
single listener and passes the merged updater state to the banner and
the Updates tab.

The tray cache recorded values before the native setters ran, so a
failed call left the tray stale. Each value is now recorded only after
its setter succeeds.

Refs #1071

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps
enaboapps marked this pull request as ready for review October 15, 2026 11:23
@enaboapps
enaboapps merged commit b8ca0fe into main Oct 15, 2026
6 checks passed
@enaboapps
enaboapps deleted the fix/1071-updater-progress branch October 15, 2026 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Updater download progress floods state emission and can freeze the app

2 participants