P2-7: Transfer concurrency, retry with backoff, partial-write safety #27
Labels
No labels
data-integrity
engine
platform
procurement
remote
scaffold
ui
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/cairn-desktop#27
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Depends on P2-6.
Goal
Make execution robust and reasonably fast without turning a flaky network into corruption or a denial-of-service against the user's own server.
Files
internal/sync/execute.go,internal/sync/retry.go,internal/sync/execute_test.gointernal/sync/engine.go1. Bounded concurrency
Run transfers through a worker pool, default 4, configurable.
Ordering still holds.
Order(Task 8) guarantees parent-before-child and child-before-parent-delete. Concurrency must not break that. The safe approach: execute in dependency layers — group operations byDepth, run each layer concurrently, and only start the next layer once the previous has finished. Never run a create and a delete concurrently.2. Retry with backoff — and knowing when not to
Retry only what can succeed on a second attempt:
423 Locked507 Quota exceeded401 Unauthorized403 ForbiddenGetting this table wrong is how a client ends up sending thousands of futile requests to a server that has already said no.
3. Partial-write safety
A file being written by another application must not be uploaded mid-write.
Before reading a file for upload, check stability: stat it, wait a short interval (~2 s), stat again. If size or mtime changed, skip this pass and pick it up next time. Uploading a half-written file produces a valid-looking sync of corrupt content, and the state DB then records it as correct.
Steps
SkipTestConvergencewith-race.git commit -s -m "feat(sync): bounded concurrency, selective retry, partial-write guard"Acceptance criteria
go test -raceis clean.Done
2849548b83— feat(sync): bounded concurrency, selective retry, partial-write guard23ca0d9487— fix(sync): re-check before PUT, settle once per pass, brake retriesWhat was built
Depth; never a create and a delete concurrently.ErrTransientfor 5xx/timeouts/resets,ErrLockedfor 423; 507/401/403 not retried); internal/sync decides only viaerrors.Is.settle(), withput/conflictcomparing against the scan's own stat.Tests
CGO_ENABLED=0, and underCGO_ENABLED=1 -raceincludingTestConvergence/TestConvergenceOnATestClock(50/50 seeds each, 0 data races) — P2-R7.23ca0d9, linux/arm64, green. Coverage total: 90.8%.Acceptance criteria
TestSyncNeverRetriesWhatAnotherAttemptCannotFix,TestSyncStopsWhenTheServerRefusesTheCredentials.TestSyncRunsOperationsConcurrentlyInOrdersLayers(pairwise start/end ordering and the exact concurrency bound at 0, 4 and 2).go test -raceis clean — full suite plusTestConvergenceunder-race, 0 warnings.Rulings
-raceruns locally withCGO_ENABLED=1as a test tool only; CI staysCGO_ENABLED=0without-race.errors.Is(no net/net-http import); sleeps are injected for tests.ErrTransient, stop retrying for the rest of the pass; a success resets the count; 423 unaffected.Deferred
settleMove's put) still send one more request before stopping; not in this round's fix list.put's Open and the PUT) are named in the code's docs and left for the final review.Implemented and reviewed by Claude (subagent-driven), landed on main after review and green CI.