Skip to content

List before watching, so an empty cluster counts as synced - #6

Merged
zhanghaohit merged 3 commits into
mainfrom
fix/sync-on-empty-list
Oct 28, 2026
Merged

zhanghaohit merged 3 commits into
mainfrom
fix/sync-on-empty-list

Conversation

@zhanghaohit

@zhanghaohit zhanghaohit commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Symptom. On a fresh cluster with no LLMSLORequirement, slo-api crash-loops: it logs cr-index not synced after 30s; serving anyway, but the liveness probe (2s delay, 10s period, 3 failures) has already killed it; a pod that survives answers /readyz with 503. Seen on a new arm64 cluster right after install.

Cause. The CR index went straight into a watch and set synced on its first event. With no CRs the API server sends no ADDED event, and its first BOOKMARK can take minutes. Clusters that already have SLOs never showed it: their ADDED events arrive at once. The test fake always sent a BOOKMARK, so the tests could not show it either.

Change. _watch_once lists first, rebuilds the index from the result (which also drops CRs deleted while no watch ran), marks it synced -- an empty list is a complete one -- and then watches from the list's resourceVersion.

Tests. tests/test_cr_index_sync.py uses a watch that stays silent, like a real API server on an empty cluster: an empty cluster must report synced, and listed CRs must be indexed before any watch event. Both fail on the old code (wait_synced stays False); with this change all 55 tests pass.

Release. Also sets pyproject.toml to 0.2.1, so the v0.2.1 tag can be cut once this merges.

The CR index went straight into a watch and marked itself synced on
the first event. On a cluster with no LLMSLORequirement there is none:
the API server sends no ADDED event and its first BOOKMARK can take
minutes. slo-api then waited its 30s for a sync that never came, the
liveness probe killed it before it served, and the pod crash-looped;
had it lived, /readyz would have stayed 503.

List first, rebuild the index from the result and mark it synced --
an empty list is a complete one -- then watch from the list's
resourceVersion. The test fake always sent a BOOKMARK, which is why
this never showed; the new tests use a watch that stays silent, and
fail on the old code.
The release with the CR index that lists before it watches.
@zhanghaohit
zhanghaohit requested a review from remotego October 28, 2026 08:54
_replace cleared the index and then re-added every CR outside the lock.
It runs on every watch reconnect, so a request in between saw no CRs and
answered a known route as unknown. Build the new index aside and swap it
in under the lock: a reader sees the old index or the new one.

The test hands _replace a generator that records what a reader sees at
each step; with the clear-then-add version it sees an empty index.
@zhanghaohit
zhanghaohit merged commit 77507d8 into main Oct 28, 2026
4 checks passed
@remotego remotego mentioned this pull request Nov 2, 2026
5 tasks done
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.

1 participant