Skip to content

fix(kds): retry sync updates on write conflicts (backport of #17738) - #17841

Merged
bartsmykla merged 2 commits into
release-2.14from
chore/backport-release-2.14-17738
Aug 19, 2026
Merged

fix(kds): retry sync updates on write conflicts (backport of #17738)#17841
bartsmykla merged 2 commits into
release-2.14from
chore/backport-release-2.14-17738

Conversation

@kumahq

@kumahq kumahq Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Automatic cherry-pick of #17738 for branch release-2.14

Generated by action

cherry-picked commit d6edc9c

鈿狅笍 鈿狅笍 鈿狅笍 Conflicts happened when cherry-picking! 鈿狅笍 鈿狅笍 鈿狅笍

On branch release-2.14
Your branch is up to date with 'origin/release-2.14'.

You are currently cherry-picking commit d6edc9c474.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	modified:   pkg/kds/v2/store/sync.go

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   pkg/kds/v2/store/sync_test.go

On a Zone, KDS sync competes with zone-local writers for the same
resources: the VIP allocator owns `Status.VIPs` and the hostname
generators own `Status.Addresses`. Stores version the whole resource
rather than its halves, so any of those writes invalidates the version
KDS read at `List` time and the downstream `Update` fails with a
conflict. On Kubernetes the store reads through an informer cache, which
can hand back an already stale version even without a concurrent writer.

The conflict propagates out of `Sync` and tears the stream down. Because
delta xDS marks a resource delivered when the response is sent, the
upstream keeps considering the zone current while it silently drifts
until the next full resync.

- Updates that lose a write conflict are collected instead of aborting
the transaction, and reapplied by `retryConflictedUpdates` after it
commits, so the backoff holds no connection or row locks.
- Each retry re-reads the stored copy and rebases the pending upstream
change onto it, taking `Status` from the fresh copy when
`IgnoreStatusChange` is set, matching what `Sync` already does when it
first decides to update.
- Up to 3 attempts with a jittered pause of at most 100ms in between,
shared by the whole batch: the first retry runs immediately, which is
all a store reading its own writes needs, and the later ones wait so a
cached store (Kubernetes informer) can observe the write that won.
- Exhausted retries return the conflict to the caller, keeping the
existing tear-down-and-resync behaviour rather than silently skipping
the resource, which would leave the zone drifting.
- Unit tests cover both the recovering case and the give-up case.

N/A

---------

Signed-off-by: Lukasz Dziedziak <lukidzi@gmail.com>
Signed-off-by: Lukasz Dziedziak <lukidzi@gmail.com>
@lukidzi lukidzi removed the conflict label Aug 3, 2026
@lukidzi
lukidzi marked this pull request as ready for review August 3, 2026 18:29
@lukidzi
lukidzi requested a review from a team as a code owner August 3, 2026 18:29
@lukidzi
lukidzi requested review from kongmesh and lukidzi August 3, 2026 18:29
@bartsmykla
bartsmykla merged commit 5b8a4e5 into release-2.14 Aug 19, 2026
16 checks passed
@bartsmykla
bartsmykla deleted the chore/backport-release-2.14-17738 branch August 19, 2026 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants