Skip to content

Perf: move Lite background pipeline + full refresh off the UI thread (P1)#1110

Merged
erikdarlingdata merged 1 commit into
devfrom
feature/perf-lite-offthread
Jun 11, 2026
Merged

Perf: move Lite background pipeline + full refresh off the UI thread (P1)#1110
erikdarlingdata merged 1 commit into
devfrom
feature/perf-lite-offthread

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

First increment of the UI-responsiveness work (P1 of the perf effort), focused on the CRITICAL Lite finding: DuckDB.NET is synchronous (verified — the shipped DLL has no async overrides) and Lite has zero ConfigureAwait(false), so all Lite DuckDB work — UI queries and the background collect/checkpoint/archive pipeline — runs on the WPF dispatcher thread.

In this PR

  • Background pipeline off the UI threadTask.Run around CollectionBackgroundService.StartAsync. Pool threads have no SynchronizationContext, so the whole collection/checkpoint/archive pipeline stays off the dispatcher. Kills the per-minute collection jank and the multi-second-to-minutes freeze on archive/reset. Verified safe: the pipeline only touches DuckDB + the email/webhook notification service; the UI polls DuckDB on its own timers (decoupled).
  • RefreshAllTabsAsync off the UI thread — the first-load / manual-refresh / time-range-change path wraps each of ~36 queries in Task.Run (correct ReaderWriterLockSlim affinity: each query acquires+releases its read lock inside one synchronous run). Bonus: the fan-out is now genuinely parallel.

Still on this effort (same pattern, not deferred)

The 60s-timer sub-tab refreshes, picker charts, status timer, drill-down, slicer, grid-selection, connect; then a bounded read lock. Then the shared-UI crosshair/hover hot path, the Dashboard timer/throttle/SQL-aggregation chunk, and the leak cluster — both apps.

Validation

  • Lite builds clean (net10).
  • Lite.Tests 428/429 — the 1 failure (CredentialProfileTests.SwitchToProfile_DeletesOrphanedPerServerSecret) is a known flake: those tests hit the machine-global Windows Credential Manager and pass 13/13 in isolation; unrelated to these edits.

⚠️ Threading change — please validate on a running Lite before merge.

🤖 Generated with Claude Code

…(P1)

Root cause (verified against the shipped DuckDB.NET.Data.dll: no async method
overrides; Lite has 0 ConfigureAwait(false)): every "await ...Async()" DuckDB
call completes synchronously on the calling thread, so all Lite data work runs on
the WPF dispatcher.

- Start CollectionBackgroundService off the UI thread (Task.Run around StartAsync).
  Pool threads have no SynchronizationContext, so the entire collection / checkpoint
  / archive pipeline now stays off the dispatcher — kills the per-minute collection
  jank and the multi-second-to-minutes freeze on archive/reset. Verified safe: the
  pipeline only touches DuckDB + the email/webhook AnalysisNotificationService; the
  UI reads data by polling DuckDB on its own timers, fully decoupled.
- RefreshAllTabsAsync (first load / manual refresh / time-range change): wrap each
  of the ~36 queries in Task.Run so the fan-out runs on pool threads instead of
  serially on the dispatcher. Each query's ReaderWriterLockSlim read lock is acquired
  AND released inside one synchronous run, so thread affinity holds. Bonus: the
  WhenAll fan-out is now genuinely parallel. UI-update code after the awaits unchanged.

Build: Lite builds clean (net10). Lite.Tests 428/429 (the 1 failure is a known flake
— CredentialProfileTests touch the machine-global Windows Credential Manager and pass
13/13 in isolation; unrelated to these edits).

Still to come on this effort (same Task.Run-wrap pattern): the 60s-timer sub-tab
refreshes, picker charts, status timer, drill-down, slicer, grid-selection, connect;
then a bounded read lock. Threading change — please validate on a running Lite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@erikdarlingdata erikdarlingdata merged commit f3c5190 into dev Jun 11, 2026
2 checks passed
@erikdarlingdata erikdarlingdata deleted the feature/perf-lite-offthread branch June 11, 2026 19:15
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