Fix submission stuck on "Saving..." (serialize save effects, backport #5145)#17
Merged
milanmajchrak merged 3 commits intoJul 9, 2026
Conversation
…chMap -> concatMap) Backport of the save-effect change from upstream PR DSpace#5145 (commit a3c14c5, first released in DSpace 10.0; not present in 8.x/9.x). The four submission save effects used switchMap. When two save actions of the same type overlap (common during editing: unguarded section/upload/save-for-later saves, save-on-change on validation errors, or an enabled autosave timer), switchMap cancels the in-flight save's inner observable AFTER it dispatched StartTransactionPatchOperationsAction (commitPending=true) but BEFORE its response handler runs. Commit/Rollback are dispatched only inside that cancelled observable, so commitPending stays true forever; the next save is then dropped by the take(1)+filter(!commitPending) guard in submitJsonPatchOperations, no SAVE_*_SUCCESS/ERROR is emitted, savePending stays true, and the form is stuck on "Saving..." until the user reloads (losing unsaved metadata). concatMap serializes the save effects so each inner observable completes (dispatching Commit/Rollback and clearing commitPending) before the next save runs, eliminating the race. Only the four save effects are changed (saveSubmission$, saveForLaterSubmission$, saveSection$, saveAndDeposit$), matching upstream. deposit/discard/updateSection intentionally keep switchMap. The improved catchError from DSpace#5145 is not backported (it depends on parseErrorResponse and action signatures not present in 8.3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deterministic reproduction on a local DSpace 8.3 stack. A Playwright script delays every submission PATCH by ~3s (models a slow save) and fires two overlapping autosaves (two edits of the autosave-on-change dc.title field). - before (base, switchMap): the second save cancels the in-flight first save mid-transaction; commitPending is orphaned true; the second save is dropped by the take(1)+filter(!commitPending) guard (only 1 PATCH ever leaves the client); savePending never resets -> footer stuck on "Saving..." for the full 18s window. - after (this PR, concatMap): the saves are serialized; the first completes and clears commitPending before the second runs; "Saving..." clears within ~4s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The before/after clips are now hosted on the separate 'pr-repro-media' branch and referenced from this PR's description, so they are no longer part of the code diff. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
milanmajchrak
merged commit Jul 9, 2026
b9c6e82
into
datashare-UoEMainLibrary-dspace-8_x
10 checks passed
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.
🎥 Reproduction — before vs after (local DSpace 8.3 Docker stack)
Reproduced end-to-end on a local stack (published
dspace/dspace:dspace-8_x-testbackend + this frontend). A Playwright script delays every submission PATCH by ~3 s (models a slow save) and fires two overlapping autosaves (two quick edits of the autosave-on-changedc.titlefield). Same simulated conditions in both runs — only the frontend code differs.BEFORE (this fork's current code — bug): the second save cancels the in-flight first save mid-transaction (
switchMap);commitPendingis orphanedtrue; the second save is silently dropped by thetake(1)+filter(!commitPending)guard (only 1 PATCH ever leaves the client);savePendingnever resets → the footer is stuck onSaving…for the full 18 s window (real user must reload and loses data).AFTER (this PR —
switchMap→concatMap): the saves are serialized; the first completes and clearscommitPendingbefore the second runs;Saving…clears within ~4 s.Objective result logged by the script (identical steps):
switchMap)concatMap)Full-quality clips/stills in the
pr-repro-mediabranch (before.mp4 · after.mp4). (The media is hosted on the separatepr-repro-mediabranch, so it is not part of this PR's code changes.)Problem
When creating/editing a submission, the form can get permanently stuck showing
Saving.... The user must reload the page, which discards the in-memory ngrx store and loses the metadata they had typed.Root cause
The four submission save effects in
submission-objects.effects.tsuseswitchMap. When two save actions of the same type overlap,switchMapcancels the in-flight save's inner observable after it dispatchedStartTransactionPatchOperationsAction(commitPending = true) but before its response handler runs.Commit/Rollbackare dispatched only inside that cancelled observable, socommitPendingstaystrueforever. The next save is then silently dropped by thetake(1) + filter(!commitPending)guard insubmitJsonPatchOperations(), so noSAVE_*_SUCCESS/SAVE_*_ERRORis emitted,savePendingstaystrue, and the UI is stuck onSaving....Overlapping same-type saves are easy during normal editing because:
dispatchSaveguardfind(isPending => !isPending)is defeated bystartWith(false)ingetSubmissionSaveProcessingStatus, so it does not actually serialize saves;submission.autosave.timeris enabled in config, the periodic autosave makes it far more frequent.Fix
Change the four save effects from
switchMaptoconcatMap.concatMapserializes them, so each inner observable completes (dispatchingCommit/Rollbackand clearingcommitPending) before the next save runs — eliminating the race.Upstream / backport
This is a backport of upstream DSpace/dspace-angular#5145 (commit
a3c14c5f,[DURACOM-453]), which first shipped in DSpace 10.0. The change is not present in any 8.x or 9.x release and was not backported upstream, so DSpace 8.3 (this fork) does not have it.Scope matches upstream exactly:
concatMap:saveSubmission$,saveForLaterSubmission$,saveSection$,saveAndDeposit$.switchMap:depositSubmission$,discardSubmission$,addAllMetadataToSectionData(nocommitPendingto orphan there).catchErrorfrom [DSpace-CRIS] Administrative Edit of archived items via submission form and security configuration for metadata visibility (Frontend) DSpace/dspace-angular#5145 is not backported — it depends onparseErrorResponse()and extended error-action signatures that do not exist in 8.3.Risk & testing
Tiny, low-risk change (1 import + 4 operators). Suggested QA: create a new submission, rapidly edit metadata / switch sections / upload while a save is in flight; confirm the form never gets stuck on
Saving.... Full CI/build recommended.🤖 Generated with Claude Code