refactor(#3255): one knowledge subject, single writer and many readers
Review call: the event was addressed per hive — `$SWARM.events.<hive>.knowledge`, published in a loop over the roster, granted through a wildcard. It does not need to be. The payload is empty and the event means the same thing to every hive, so one publish to one subject delivers exactly what N publishes to N subjects did, and core NATS already fans out to whoever is subscribed. A hive that was down misses it either way and reconciles on its next periodic pull. That deletes rather than reshuffles: the roster loop, the wildcard, and the shared subject-building function whose entire purpose was keeping the grant and the publish from drifting apart. With one literal there is nothing to disagree about. The per-hive shape was justified by the callout policy's rule that an extra subject must contain the hive name. That rule governs `extra_hive_subjects` — what a HIVE may publish. This subject lives in the controller's reader grant, which the rule does not constrain, so a real rule was carried across into a decision it had no authority over. Knowledge becomes its own category rather than a leaf under a general event namespace, since a namespace shaped for events that do not exist yet is a decision made before there is anything to decide from. The empty config-PR match arm goes with it: an arm with no body claims this is where the deploy path is handled, and it is not. The deny test stays and matters more, not less: with one shared subject a forged event would reach the whole swarm where a per-hive one reached a single hive.
This commit is contained in:
parent
84125b0806
commit
9b939f4626
6 changed files with 104 additions and 156 deletions
|
|
@ -135,12 +135,7 @@ pub fn spawn(
|
|||
// paths independent reconnect state, so one could be serving while
|
||||
// the other was still down. `async_nats::Client` is a handle, so the
|
||||
// clone is cheap.
|
||||
tokio::spawn(drain_swarm_events(
|
||||
client.clone(),
|
||||
hive.clone(),
|
||||
coord,
|
||||
shutdown.clone(),
|
||||
));
|
||||
tokio::spawn(drain_swarm_events(client.clone(), coord, shutdown.clone()));
|
||||
|
||||
let mut health = SweepHealth::new("swarm_status_publish", "warn", FAILURES_BEFORE_BANNER);
|
||||
loop {
|
||||
|
|
@ -179,7 +174,7 @@ pub fn spawn(
|
|||
});
|
||||
}
|
||||
|
||||
/// Listen on this hive's swarm-event subject and act on what arrives.
|
||||
/// Listen on the swarm's knowledge-event subject and act on what arrives.
|
||||
///
|
||||
/// The controller decides *what a forge delivery means* and addresses the
|
||||
/// result here; this end does not know a forge exists. Today the one event is
|
||||
|
|
@ -211,12 +206,14 @@ pub fn spawn(
|
|||
/// changes, the server log is the thing that knows why — nothing here will say.
|
||||
async fn drain_swarm_events(
|
||||
client: async_nats::Client,
|
||||
hive: String,
|
||||
coord: std::sync::Arc<crate::coordinator::Coordinator>,
|
||||
mut shutdown: tokio::sync::watch::Receiver<bool>,
|
||||
) {
|
||||
let subject = swarm_queue_client::events::knowledge(&hive);
|
||||
let mut sub = match client.subscribe(subject.clone()).await {
|
||||
// One subject for the whole swarm, so this hive's own name never enters
|
||||
// it: the controller publishes once and core NATS fans out to whoever is
|
||||
// subscribed.
|
||||
let subject = swarm_queue_client::knowledge::SUBJECT;
|
||||
let mut sub = match client.subscribe(subject).await {
|
||||
Ok(sub) => sub,
|
||||
Err(e) => {
|
||||
// Warn rather than a boot banner: the hive is fully functional
|
||||
|
|
|
|||
Loading…
Reference in a new issue