Replica mirror (the local Snapshot) #10

Merged
ginjiruu merged 1 commit from feat/replica-mirror into master 2026-09-14 13:17:32 +00:00
Owner

Closes #4

Implements the replica mirror: every replica watches the managed Registry Secret and the referenced per-App Secrets and maintains its local in-memory Snapshot — rebuilt whole and atomically swapped on any change, never leader-gated.

What

  • internal/snapshot — the new package:
    • Build (pure, Seam 2 per spec #1): Registry + watched-Secret bytes → an immutable Snapshot; the hostname index and the App set are built together in one pass and can never disagree; input-isolated (deep-copied). Per-App bytes-present is derived from the local watch (absent Secret or missing key → false → 5xx, the App is kept, ADR-0006); the leader's secretReady flag is zeroed in the copy — the local App.SecretReady is the served 5xx flag.
    • Coalesce: a burst of events leaves at most one signal queued (buffered-1, non-blocking signal) — at most one in-flight rebuild plus one follow-up.
    • Mirror: subscribes to the cluster-wide Secret informer (registry + referenced-Secret events, per-replica watched set re-derived on Registry change), bootstraps from the current cluster state (absent Registry Secret is valid; absent referenced Secret → 5xx — no leader round-trip), and runs the coalesced rebuild loop with a whole-block atomic pointer swap. Current() is a single atomic.Pointer load (lock-free). NeedLeaderElection() == false puts it in the manager's "others" runnable group — without it a plain Runnable is classified into the leader-election group and only the leader would mirror (caught in review).
  • cmd/main.go — the Mirror registered as a manager runnable (not leader-gated).

Acceptance criteria

  • Rebuild + atomic pointer swap on Registry/referenced-Secret change: envtest (pointer-swap spec) + Consistently whole-state invariant while the Registry churns.
  • Lock-free read: single atomic.Pointer load; the write mutex is never held on the read path (plus go test -race).
  • Hostname index + App set built together: unit + per-read invariant assertion.
  • Rapid changes coalesced: unit pins a 10-signal burst → ≤2 rebuilds; envtest pins final-state convergence.
  • Bytes-present flips on delete/recreate: envtest (delete → false/5xx, App kept; recreate → true with new bytes).
  • Fresh replica bootstrap without a leader round-trip: envtest spec runs no leader-side component at all, against a manager with leader election enabled (the production wiring, mgr.Add(mirror)).

Judgement calls

  • parseRegistry keeps last-good state on a malformed Registry document (the served Snapshot is never blanked by a bad write) — not in the ACs, harmless, matches the ADR last-good spirit.
  • Rebuilds() counter: observable behaviour the AC testability needs (burst spec).

Notes

  • RBAC: new replica-side marker (secrets get;list;watch) on mirror.go declares the mirror's own read need (previously covered only transitively by the leader's marker); make manifestsconfig/rbac/role.yaml unchanged (verb union identical).
  • The ADR-0005 failover gap (leader Resolvent last-good is in-process; a new leader re-resolves on outage) is intentionally not in this ticket — not an AC here; candidate for a follow-up (seed resolvents from the last written Registry Secret on leader acquisition).
Closes #4 Implements the replica mirror: every replica watches the managed Registry Secret and the referenced per-App Secrets and maintains its local in-memory Snapshot — rebuilt whole and atomically swapped on any change, never leader-gated. ## What - `internal/snapshot` — the new package: - `Build` (pure, Seam 2 per spec #1): Registry + watched-Secret bytes → an immutable Snapshot; the hostname index and the App set are built together in one pass and can never disagree; input-isolated (deep-copied). Per-App bytes-present is derived from the local watch (absent Secret or missing key → false → 5xx, the App is kept, ADR-0006); the leader's `secretReady` flag is zeroed in the copy — the local `App.SecretReady` is the served 5xx flag. - `Coalesce`: a burst of events leaves at most one signal queued (buffered-1, non-blocking signal) — at most one in-flight rebuild plus one follow-up. - `Mirror`: subscribes to the cluster-wide Secret informer (registry + referenced-Secret events, per-replica watched set re-derived on Registry change), bootstraps from the current cluster state (absent Registry Secret is valid; absent referenced Secret → 5xx — no leader round-trip), and runs the coalesced rebuild loop with a whole-block atomic pointer swap. `Current()` is a single `atomic.Pointer` load (lock-free). `NeedLeaderElection() == false` puts it in the manager's "others" runnable group — without it a plain `Runnable` is classified into the leader-election group and only the leader would mirror (caught in review). - `cmd/main.go` — the Mirror registered as a manager runnable (not leader-gated). ## Acceptance criteria - Rebuild + atomic pointer swap on Registry/referenced-Secret change: envtest (pointer-swap spec) + `Consistently` whole-state invariant while the Registry churns. - Lock-free read: single `atomic.Pointer` load; the write mutex is never held on the read path (plus `go test -race`). - Hostname index + App set built together: unit + per-read invariant assertion. - Rapid changes coalesced: unit pins a 10-signal burst → ≤2 rebuilds; envtest pins final-state convergence. - Bytes-present flips on delete/recreate: envtest (delete → false/5xx, App kept; recreate → true with new bytes). - Fresh replica bootstrap without a leader round-trip: envtest spec runs no leader-side component at all, against a manager with leader election enabled (the production wiring, `mgr.Add(mirror)`). ## Judgement calls - `parseRegistry` keeps last-good state on a malformed Registry document (the served Snapshot is never blanked by a bad write) — not in the ACs, harmless, matches the ADR last-good spirit. - `Rebuilds()` counter: observable behaviour the AC testability needs (burst spec). ## Notes - RBAC: new replica-side marker (`secrets get;list;watch`) on `mirror.go` declares the mirror's own read need (previously covered only transitively by the leader's marker); `make manifests` — `config/rbac/role.yaml` unchanged (verb union identical). - The ADR-0005 failover gap (leader Resolvent last-good is in-process; a new leader re-resolves on outage) is intentionally **not** in this ticket — not an AC here; candidate for a follow-up (seed resolvents from the last written Registry Secret on leader acquisition).
add replica mirror: local snapshot, non-leader-gated, atomic swap, coalesced rebuilds
Some checks failed
Lint / Run on Ubuntu (push) Has been cancelled
E2E Tests / Run on Ubuntu (push) Has been cancelled
Tests / Run on Ubuntu (push) Has been cancelled
Lint / Run on Ubuntu (pull_request) Has been cancelled
E2E Tests / Run on Ubuntu (pull_request) Has been cancelled
Tests / Run on Ubuntu (pull_request) Has been cancelled
7980a91bea
ginjiruu merged commit 581e24742b into master 2026-09-14 13:17:32 +00:00
Sign in to join this conversation.
No reviewers
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lab/authz-bridge!10
No description provided.