fix(reconcile): batch startup reconcile into fixed round trips, bound central work by QueryTimeout, retry failed site passes with back-off (review 2026-10-21 03/P-1)

This commit is contained in:
Joseph Doherty
2026-10-22 06:25:57 -04:00
parent d6a9a79c27
commit 7c83a4aa94
9 changed files with 638 additions and 130 deletions
@@ -207,6 +207,22 @@ a cancelled bulk deploy can be left holding its lock.
one, so the two entry points cannot drift on deployment identity, idempotency, lock
coverage, or optimistic concurrency.
### Startup-reconcile staging
A site node that missed a deploy reports its inventory on startup and central
(`Communication/ReconcileService`) stages fresh `PendingDeployment` fetch tokens for
the gap. The pass costs a **fixed number of round trips whatever the gap size**
(review 2026-10-21 03/P-1): the expected-set projection (no config JSON), ONE
untracked read of the gap instances' snapshot configs
(`GetDeployedSnapshotsByInstanceIdsAsync`), and ONE batched insert-if-absent
(`StagePendingBatchIfAbsentAsync` — expired rows deleted set-based, live rows from an
in-flight deploy or the peer node's concurrent reconcile handed back instead of
superseded, one `SaveChanges`; a failed batch save falls back to per-row staging so
one bad row costs only itself). Central's work is bounded by `QueryTimeout`, the
site's own deadline for the reply. On the site, `SiteReconciliationActor` retries a
failed or partially-failed pass up to **3** times with exponential back-off (30 s,
60 s) instead of waiting for the next node restart.
### Terminal deployment-record retention
Deployment records are insert-only — one row per deploy attempt — so without a