Skip to content

fix: Retry status write races and skip deleted objects - #1375

Merged
scotwells merged 2 commits into
mainfrom
fix/status-apply-reconcile-noise
Nov 6, 2026
Merged

scotwells merged 2 commits into
mainfrom
fix/status-apply-reconcile-noise

Conversation

@scotwells

@scotwells scotwells commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Scot Schuchert-Wells

What

The bgpadvertisement and trafficpolicybinding controllers in galactic-controller report reconcile errors for races that resolve on their own:

  • The BGPAdvertisement projection updates NetworkInterface, claim and VPCAttachment status that network-services-operator also writes, each side from a cached copy. Whoever writes second gets a conflict.
  • A TrafficPolicyBinding is often deleted with its interface between the read and the status apply, so the apply returns not-found.
  • A status write to an interface, claim or attachment that was deleted mid-pass returns not-found.

These errors keep the reconcile error floor alert firing. They don't point to any real fault.

Change

  • bgpadvertisement: a conflict now requeues with backoff instead of returning an error. A status write to an interface, claim or attachment that was deleted mid-pass is a no-op.
  • trafficpolicybinding: a not-found status apply means the binding is gone, so the reconcile ends cleanly.
  • Every other error still surfaces.

Tests cover each case and confirm that other errors still surface. Each new test fails without the fix.

A companion network-services-operator change, datum-cloud/network-services-operator#884, handles the same races on its side.

The BGPAdvertisement projection writes NetworkInterface, claim and
VPCAttachment status that NSO also writes, from cached copies. A lost race
was returned as a reconcile error; requeue instead. A status write to an
interface or claim deleted mid-pass is not an error either.

A TrafficPolicyBinding often goes with its interface between the read and
the status apply. A not-found apply means there is no status to report.

@ecv ecv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve.

Conflicts requeue through the rate-limited workqueue (bounded backoff, fresh cached read next pass), and NotFound is skipped only on status writes after the object is gone, never on a path that does deletion work.

  • No blind overwrite: the writes stay Status().Update carrying the read resourceVersion, so a lost race still returns Conflict and is retried, not forced. The per-attachment loop is idempotent, so re-running after a mid-loop conflict is safe.
  • bgpadvertisement_controller.go skips only on NotFound from a status write (clearWithdrawnAdvertisement, attachment/interface/claim projection). It does not key off DeletionTimestamp, so withdrawal clearing and the APIReader confirmation on the NotFound-at-read path are unchanged. Nothing that must run during deletion is skipped.
  • #1369 (attachment without a node maps to all tenant advertisements) fans more reconciles at the same attachments, so this conflict path will be hit more often. It stays fine: Conflict is a debug log plus requeue, not an error metric.
  • reconcilers.go: NotFound on the binding SSA status patch returns nil. Right, since the binding has no status once gone.

Follow-ups:

  • Requeue: true has no cap beyond the workqueue's per-item exponential backoff; a persistent conflict (two controllers fighting over a condition) would retry forever at the max delay with only a V(1) log. Consider a counter metric for conflict requeues.
  • The test covers only the interface-status write; attachment and claim writes share the same handling but have no test.

@scotwells
scotwells merged commit 20beab1 into main Nov 6, 2026
28 checks passed
@scotwells
scotwells deleted the fix/status-apply-reconcile-noise branch November 6, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants