feat(broker): broadcast config changes to all replicas via fanout - #628
Draft
mahlunar wants to merge 1 commit into
Draft
feat(broker): broadcast config changes to all replicas via fanout#628mahlunar wants to merge 1 commit into
mahlunar wants to merge 1 commit into
Conversation
Enable running release-manager as N replicas with fresh reads on every replica. On a config-repo push the GitHub webhook syncs master, reads the new HEAD, and broadcasts a ConfigChangedEvent over a dedicated fanout exchange. Each replica binds its own server-named, auto-delete queue and syncs its local clone unless its HEAD already matches (skip-if-current). A ~60s ticker backstops missed broadcasts. The existing quorum + single-active-consumer flow queue is unchanged, so write flows stay serialized fleet-wide with HA failover. Closes DMAT-365 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Enable running the release-manager as N replicas with fresh reads on every replica, implementing the fanout-broadcast approach from
docs/multi-replica-analysis.md.Today the read APIs (
/status,/describe/*,/policies) serve from a per-replica local clone that is refreshed only when that replica receives the GitHub push webhook. Behind a load balancer the webhook hits exactly one replica, so the others serve stale data indefinitely. This change makes every replica sync on every push via a fanout broadcast, with a coarse ticker as a backstop.Changes
broker.Broker—PublishBroadcastandStartBroadcastConsumer. Theamqpextraimpl backs them with a dedicated fanout exchange and a per-replica server-named, auto-delete queue (every replica receives every message; queue is removed on disconnect). Deliveries are acked unconditionally — skip-if-current makes the handler idempotent. Thememorybroker fans out in-process for dev/test.ConsumerConfig.Fanout(fanout exchange + server-named/auto-delete queue, no single-active-consumer) andPublishDto.ExchangeType(defaults totopic). The existing flow-queue declaration (quorum + SAC) is byte-for-byte unchanged.events.ConfigChangedEvent{SHA}implementingbroker.Publishable, andgit.Service.MasterHash(ctx)reading HEAD under the existingRLock.SyncMaster→ readMasterHash→ broadcast the SHA (log-only on failure, still returns 200), via an injected hook matching the existing publish-hook idiom.start.gostarts the broadcast consumer (skip-if-current, elseSyncMaster) and a~60sticker backstop in their own goroutines.--amqp-broadcast-exchange(defaultrelease-manager-broadcast) and--config-repo-sync-interval(default60s).ConfigChangedEventand a behavioral publish→consume test for the memory broadcast path.Why
Write flows are already multi-replica safe (the AMQP queue is a quorum queue with
x-single-active-consumer, giving HA failover). Stale reads on replicas that didn't receive the webhook are the only blocker to running N replicas — this closes that gap with sub-2s freshness propagation while leaving the write path untouched.Notes for reviewers
exclusive: true. The makasim/amqpextra consumer treats queue-source options as mutually exclusive, soWithExchangeis used instead — yielding a server-named, auto-delete queue bound to the fanout exchange. Functionally equivalent here (per-replica, auto-cleaned, no SAC, receives every message); only connection-level exclusivity is dropped, which adds nothing given the queue name is server-generated and only this consumer binds to it.Prefetchon the broadcast consumer was set to1(backpressure for the single worker) and a fanout-mode shutdown log line was corrected as part of that review. No blocking issues found.Closes DMAT-365
Note
Medium Risk
Touches AMQP topology and fleet-wide git sync behavior; misconfiguration or broadcast failures could leave replicas stale until the ticker heals, but write flows and the existing quorum SAC queue are unchanged.
Overview
Adds multi-replica config freshness so every pod’s local config clone stays aligned after a config-repo push, not only the replica that receives the GitHub webhook.
Broker broadcast path:
broker.BrokergainsPublishBroadcast/StartBroadcastConsumer. AMQP uses a separate fanout exchange and per-replica server-named auto-delete queues (ConsumerConfig.Fanout, configurableExchangeTypeon publish). The in-memory broker mirrors this for dev/tests.Event + git: New
ConfigChangedEventcarries the new master SHA; replicas callMasterHashand skipSyncMasterwhen already current.Wiring: After webhook
SyncMaster, the handler reads HEAD and broadcasts via an injected hook (failures are log-only, still HTTP 200).start.goruns a broadcast consumer plus a ~60sSyncMasterticker backstop. Flags:--amqp-broadcast-exchange,--config-repo-sync-interval.Docs/tests:
docs/multi-replica-analysis.mddocuments the design; tests cover the event and memory broadcast delivery.Reviewed by Cursor Bugbot for commit a9a62d2. Configure here.