Skip to content
This repository was archived by the owner on Aug 5, 2026. It is now read-only.

fix(status): retry UpdateStatus on optimistic-concurrency conflict (krateo-core-provider#57) - #26

Merged
braghettos merged 2 commits into
mainfrom
fix/status-update-retry-conflict
Jul 30, 2026
Merged

fix(status): retry UpdateStatus on optimistic-concurrency conflict (krateo-core-provider#57)#26
braghettos merged 2 commits into
mainfrom
fix/status-update-retry-conflict

Conversation

@braghettos

Copy link
Copy Markdown
Collaborator

What

Make the composition-dynamic-controller retry its status writes on optimistic-concurrency conflicts, so a benign the object has been modified 409 no longer wedges the reconcile.

Fix #1 of the layered plan in the RCA on krateo-platformops/core-provider#57 (#2#4 tracked there).

Why

tools.UpdateStatus submits the composition CR with whatever resourceVersion it was read at and does no retry — one 409 aborts the entire reconcile. During a GVK-migration handover (every version bump), the retiring per-version controller and the newly-started one briefly contend on the same CR's status, so that 409 is routine. When it hits, the healthy Ready=True/Synced=True condition never gets written and the composition stays wedged Ready=False until someone manually restarts the controller — the exact symptom in krateoplatformops#57 (alongside the another operation in progress dry-run error, addressed by fix #2).

Change

  • New updateStatusWithRetry (internal/composition/status_update.go) — a drop-in replacement for tools.UpdateStatus that, on apierrors.IsConflict, re-fetches the latest object, re-applies the status this reconcile computed, and retries (retry.RetryOnConflict / retry.DefaultRetry). Last-writer-wins is correct here because this controller owns the status subresource.
  • Rewired all 7 status-write sites in composition.go through it (the 6 tools.Update non-status calls are untouched).
  • Non-conflict errors propagate immediately (unchanged behavior); an explicit otel.endpoint-style override is N/A here.

Tests

internal/composition/status_update_test.go (plain unit tests, dynamicfake + reactor):

go build ./..., go vet ./..., gofmt, and the full internal/composition package all pass; go.mod/go.sum unchanged.

Scope

This removes the status-conflict wedge. The companion dry-run another operation in progress behavior, the handover ordering, and diagnostic logging are fixes #2#4 in the RCA and remain tracked on krateo-platformops/core-provider#57.


🤖 Generated with Claude Code

tools.UpdateStatus submits the composition CR with whatever resourceVersion it
was read at and performs no retry, so a benign "the object has been modified"
409 aborts the whole reconcile. During a GVK-migration handover the retiring
per-version controller and the new one briefly contend on the same CR's status,
making that 409 routine — the healthy Ready/Synced condition then never lands
and the composition stays wedged Ready=False until a manual controller restart.

Add updateStatusWithRetry (a drop-in for tools.UpdateStatus) that retries on
conflict by re-fetching the latest object and re-applying the computed status;
last-writer-wins is correct since this controller owns the status subresource.
Wire all 7 status-write sites in composition.go through it, with unit tests
covering conflict-recovery, non-conflict propagation, and the happy path.

Refs krateo-platformops/core-provider#57 (fix #1 of the layered plan; #2-#4
tracked on the issue).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first cut snapshotted mg's status via unstructured.NestedFieldCopy to
re-apply it on conflict, but NestedFieldCopy runs runtime.DeepCopyJSONValue,
which panics ("cannot deep copy composition.ManagedResource") — the composition
CR's in-memory status can hold typed values, not pure JSON. The integration
TestController/Setup/Create exercised that path.

Carry mg's status as-is and, on a 409, refresh only its resourceVersion before
retrying — no status deep-copy. On the no-conflict path the behavior is now
identical to the original tools.UpdateStatus call.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@braghettos
braghettos merged commit 3d32012 into main Jul 30, 2026
3 checks passed
@braghettos
braghettos deleted the fix/status-update-retry-conflict branch July 30, 2026 14:46
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant