Fix and finish background processing mode (opt-in) - #1054
Merged
Conversation
…changed) The background sync path (SyncProcessingMode.Background) existed but was half-wired: it passed the per-run requestId as the long-running-operation *type* (so allowConcurrentExecution never worked), discarded the enqueue result, and returned an unrelated id the client could never use to check on the run. There was no way to poll progress or reattach after a page reload, and export-to-file downloaded before the export had actually finished. - Give each run a stable operation type (uSync:<Action>) and thread the real operation id back to the client; surface an "already running" rejection instead of reporting a phantom success. - Add GET Status/Running endpoints backed by a small per-run progress cache, so the client can poll for progress and reattach to a run it didn't start itself (e.g. after F5). Cache entries expire after an hour. - Fix export-to-file timing in the client - it now downloads on actual completion instead of immediately after the background enqueue returns. - De-static a shared Stopwatch in SyncActionService that made elapsed-time tracking a cross-run/cross-user race; key it by requestId instead. - Make status polling staleness-aware: a crashed/restarted server used to leave the client stuck reporting "running" indefinitely (Umbraco's GetStatusAsync doesn't expire a stale Enqueued/Running row the way GetByTypeAsync does). Now self-heals within Umbraco's expiration window, plus a manual "reset this view" escape hatch in the UI for when that's not fast enough. - Poll only as a SignalR fallback (not unconditionally every 2s) and back off while a run drags on - the earlier fixed interval was itself enough concurrent DB traffic to trigger SQLite 'table is locked' errors during a background import. - Keep ProcessingMode defaulting to Normal - this is opt-in, not a default change mid-version. Document the SQLite locking caveat for anyone who turns Background mode on (docs/perf/background-processing-mode.md). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace the full-width "reset this view" button with a compact icon-only dismiss (top-right of the alert), styled to match the banner's own colours so it blends in rather than competing for attention - it's a rarely-needed escape hatch, not a primary action. - Move the banner to the top of the page so it's the first thing seen regardless of scroll position or other banners/content below it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Give GetOperationStatusAsync/GetRunningOperationAsync default interface implementations instead of requiring every implementer to add them. ISyncManagementService is public, so an external implementation of it would otherwise fail to compile against this change; the defaults report "not supported"/"nothing running" - safe, honest answers for an implementation that predates background processing - and uSyncManagementService's own explicit overrides still take precedence as normal. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SyncProcessingMode.Backgroundpath: the run's requestId was being passed as the long-running-operation type (so the concurrency guard never worked), the enqueue result was discarded, and the client got back an unrelated id it could never use to check on the run.GET Status/GET Runningendpoints, backed by a small per-run progress cache, so the client can poll progress and reattach to a run after a page reload.StopwatchinSyncActionServicethat made elapsed-time logging a cross-run/cross-user race.GetStatusAsyncdoesn't expire a stale row the wayGetByTypeAsyncdoes. Now self-heals within Umbraco's expiration window (~5 min default), plus a manual dismiss escape hatch in the UI for when that's not fast enough.'table is locked'errors during a background import.Scope decision
ProcessingModestays defaulted toNormal- this makes Background mode functional and safe to opt into, not a default change mid-version. SQLite-specific locking behavior is documented for anyone who turns it on: docs/perf/background-processing-mode.md.API compatibility
ISyncManagementService(public) gained two new members (GetOperationStatusAsync,GetRunningOperationAsync), given default interface implementations ("not supported"/"nothing running") so an existing external implementation of the interface keeps compiling and behaves sensibly without needing to add them. Also checkeduSync.Complete(our own downstream consumer) - it doesn't implement this interface, so unaffected either way.Test plan
dotnet buildonuSync.Backoffice.Management.ApianduSync.BackOffice- cleandotnet test uSync.Tests- 141/141 passingtsc --noEmitand fullnpm run build(tsc + vite) - cleandocs/perf/background-processing-mode.mdfor the verification checklist🤖 Generated with Claude Code