Skip to content

Cancel superseded async page loads to fix stale-load race#100

Merged
dfederm merged 1 commit into
mainfrom
dfederm/jellybox-async-load-cancellation
Jun 21, 2026
Merged

Cancel superseded async page loads to fix stale-load race#100
dfederm merged 1 commit into
mainfrom
dfederm/jellybox-async-load-cancellation

Conversation

@dfederm

@dfederm dfederm commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What & why

Page ViewModels started their data loads as fire-and-forget async work with no
cancellation, so a superseded load's post-await continuation could overwrite newer
view-model state. The most reproducible case: rapidly changing a library's sort or
filters could leave the grid showing the results of an earlier selection.

This introduces a small shared CancellableLoad helper that owns a
CancellationTokenSource, cancels any prior in-flight load when a new one starts, and
swallows the superseded OperationCanceledException. HomeViewModel, LibraryViewModel
(including every sort/filter refresh path), and ItemDetailsViewModel route their load
entry points through it and thread the cancellation token into each Kiota GetAsync call,
so a superseded request is cancelled at the HTTP layer. Terminal state commits are guarded
with ThrowIfCancellationRequested so an already-completed request can't write stale state,
and IsLoading is only cleared by the surviving load.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Build / tooling
  • Docs

Checklist

  • Single-purpose: this PR makes one logical change and does not club
    together unrelated changes.
  • Builds clean: msbuild JellyBox.sln -t:Build -p:Configuration=Debug -p:Platform=x64
    succeeds with 0 warnings and 0 errors.
  • UI/UX changes include screenshots or a short screen recording — N/A; this is a
    data-loading correctness fix with no visual or layout change.
  • Manual testing is described below.
  • Linked the related issue above (if one exists) — no tracking issue.

Manual test notes

Windows desktop — rapidly toggled a library's sort direction, sort option, and filters in
quick succession. The grid consistently settles on the final selection's results, and the
loading indicator clears correctly.

Screenshots / recording

N/A — no visual or layout change; this is a data-loading correctness fix.

Out of scope / follow-ups

None.

Page ViewModels started their data loads as fire-and-forget async work with
no cancellation (HomeViewModel.Initialize and ItemDetailsViewModel.HandleParameters
were async void; LibraryViewModel fired `_ = InitializeAsync()` and
`_ = RefreshItemsAsync()` from every sort/filter change). A superseded load's
post-await continuation could overwrite newer view-model state - for example,
rapidly toggling library filters could leave the grid showing the results of an
earlier selection.

Introduce a small shared CancellableLoad helper that owns a CancellationTokenSource,
cancels any prior in-flight load when a new one starts, and swallows the superseded
OperationCanceledException. Each affected ViewModel routes its load entry points
through it and threads the cancellation token into every Kiota GetAsync call, so a
superseded request is cancelled at the HTTP layer. Terminal state commits are guarded
with ThrowIfCancellationRequested so an already-completed request cannot write stale
state, and IsLoading is only cleared by the surviving load.
@dfederm dfederm merged commit b2729fb into main Jun 21, 2026
1 check passed
@dfederm dfederm deleted the dfederm/jellybox-async-load-cancellation branch June 21, 2026 06:56
CyberoniOntoni added a commit to CyberoniOntoni/JellyBox that referenced this pull request Jun 23, 2026
Rebased onto main with conflict resolution against dfederm#93 (controller shell), dfederm#97 (packaging), and dfederm#100 (CancellableLoad).

- Add shell search bar, Search page, and ShellFocusCoordinator
- Fix library filter XY-focus in code-behind; up-from-home focuses search
- Route collection folders via CollectionNavigation; async item lookup for search
- Keep CancellableLoad for ItemDetails/SearchViewModel; add CancelAsync for navigate-away
- ItemDetails null-safety and ResetDisplayState on reload
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