The bus on NATS: both transports behind seams, and the rollout switch #87

Merged
jschoubben merged 40 commits from feat/nats-genesis into main 2026-09-27 17:36:41 +00:00
3 changed files with 64 additions and 2 deletions
Showing only changes of commit 5fcde512bc - Show all commits
+8
View File
@@ -27,6 +27,14 @@ const TheBuildMachine = "mesh-build-machine"
func BuildWork() string { return "mesh.seat." + TheBuildMachine + ".accept.build" }
func BuildOutcome() string { return "mesh.seat." + TheBuildMachine + ".event.built" }
// KeyRoleBuilt is the build outcome under the role's name, on the bus the mesh runs on today.
//
// The same event as KeyModuleBuilt and published beside it, because a catalogue installed before this
// change listens for the module's name and one installed after listens for the role's. Both, until
// this bus retires: a rename needs publisher and subscriber to change together, and a deployment
// cannot promise which arrives first.
const KeyRoleBuilt = "built"
// Builders is how work reaches a build machine and how the outcome comes back.
type Builders interface {
// Submit asks for one build and waits for its outcome.
+20 -2
View File
@@ -161,8 +161,26 @@ func (b *currentBuild) Announce(ctx context.Context, result BuildResult) error {
if result.Failed != "" || result.Commit == "" {
return nil
}
return EmitEvent(ctx, OverCurrent{Channel: b.channel}, KeyModuleBuilt, "builder", b.on,
announcementOf(result))
// **Announced under both names on this bus, for exactly as long as this bus lives.**
//
// A build's outcome belongs to the role now (novox/hq ADR 0121), so a catalogue built from the
// current manifests listens for the role's name. A catalogue that is *already running* listens for
// the module's, because that is what it was told when it was installed. A rename on a live bus
// needs the publisher and the subscriber to change together, and a merge cannot promise that: one
// of them is deployed first, and in that window the graph silently stops being updated — which is
// the failure this whole change was cleaning up after.
//
// So both, and the order stops mattering. The module's own name goes with the bus, in step 5's
// retirement list; nothing has ever run on the bus being built, so there is no legacy name there
// and this doubling has no counterpart.
announced := announcementOf(result)
if err := EmitEvent(ctx, OverCurrent{Channel: b.channel}, KeyModuleBuilt, "builder", b.on,
announced); err != nil {
return err
}
return EmitEvent(ctx, OverCurrent{Channel: b.channel}, KeyRoleBuilt, TheBuildMachine, b.on,
announced)
}
func (b *currentBuild) Done() error { return b.delivery.Ack(false) }
+36
View File
@@ -0,0 +1,36 @@
package link
import (
"strings"
"testing"
)
// **The old bus announces a build under both names, and that is not belt-and-braces.**
//
// A build's outcome belongs to the role now, so a catalogue built from the current manifests listens
// for the role's name — and a catalogue already running listens for the module's, because that is what
// it was told when it was installed. A rename on a live bus needs publisher and subscriber to change
// together, which a deployment cannot promise: one arrives first, and in that window the module graph
// silently stops being updated.
//
// Caught by asking what merging this would do to the mesh that is actually running, which is the only
// place the question could have been asked — the tests were green and both buses were self-consistent.
func TestTheOldBusAnnouncesABuildUnderBothNames(t *testing.T) {
// The routing key a catalogue installed before the change is bound to.
if KeyModuleBuilt != "module.builder.built" {
t.Fatalf("the module's own name is %q; a catalogue already running is bound to the old one",
KeyModuleBuilt)
}
// And the local name a catalogue built from the current manifests declares, which the old bus's
// client turns into `module.<role>.built`.
if KeyRoleBuilt != "built" {
t.Fatalf("the role's event is %q, and a holder emits its verbs bare", KeyRoleBuilt)
}
if TheBuildMachine != "mesh-build-machine" {
t.Fatalf("the role is %q", TheBuildMachine)
}
// The two must differ, or one publish would serve both and this doubling would be pointless.
if strings.HasSuffix(KeyModuleBuilt, "."+TheBuildMachine+"."+KeyRoleBuilt) {
t.Fatal("the two names are the same, so nothing was renamed and this is dead weight")
}
}