fix(core): prevent orphan sites from failed SiteCreate; null-safe SiteDelete#4696
Merged
Merged
Conversation
…lete (closes #4695) Co-Authored-By: Claude Opus 4.8 <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.
Closes #4695.
Problem
Core.SiteCreateregisters a site remotely and commits the localSitesrow, then creates the EntityItems / Unit / Worker / SiteWorker in separate non-transactional steps with no rollback. If any step throws, theSitesrow is left active with no Worker/SiteWorker — an orphan that permanently blocks recreating a worker by that name (downstreamSites.Nameduplicate check). Separately,Core.SiteDeleteNRE'd on worker-less sites (siteWorkerDto/WorkerUiddereferenced unguarded), so it couldn't be used to recover orphans.Fix
SiteCreatecompensating cleanup: track the remotely-created site uid (and worker uid, if reached) and, on exception, remove them viaAdvanced_SiteItemDelete(site + entity items + remote deregister + local soft-delete) andAdvanced_WorkerDelete(worker). Each cleanup is wrapped so it never masks the original exception, which is always re-thrown. Cleanup routes throughAdvanced_SiteItemDelete(notSiteDelete) deliberately:SiteDelete→SiteReadSimplecalls.First()on the SiteWorkers set and throws on worker-less sites, so it cannot clean an orphan;Advanced_SiteItemDeleteremoves the site directly.SiteDeletenull-safety: guardsiteDto.WorkerUid != nullandsiteWorkerDto != nullso deleting a site with no SiteWorker no longer NREs and still soft-deletes the site + entity items. Happy path (fully-formed worker) unchanged.Core_Advanced_SiteItemDelete_OnSiteWithoutSiteWorker_SoftDeletesSite— arranges a worker-less orphan site and asserts it is soft-deleted without throwing.Notes / limitations
Advanced_SiteItemDeleteonly soft-deletes the local row when the remote deregister succeeds; a remote failure leaves the local orphan. This mirrors the existing primitive contract and is covered operationally by the downstream plugin mitigation (fix(workers): clean up orphan SDK site so deleted/failed workers don't block name reuse eform-backendconfiguration-plugin#1004), which cleans the local row by name. A belt-and-suspenders compensation-local forced soft-delete could be a follow-up.🤖 Generated with Claude Code