Announce the build agent's verbs, let a waiting build hear its cancel, and retry a stopped rollout (hq ADR 0219)

The holder's verbs were served and found by nothing; it now answers discovery
with its machine's four, as a runtime announces a seat's verb, so the console
finds <node>/node-build-agent.kill. A cancel publishes no outcome, so a build
waited for also looks at the cancelled set. A plan that stopped at its first
machine is retried by sending that machine the module again, unless a newer
plan holds it.
This commit is contained in:
jochen
2026-10-05 19:26:40 +02:00
parent 106507b1d3
commit 541603c15c
7 changed files with 273 additions and 7 deletions
+36
View File
@@ -229,3 +229,39 @@ func TestNatsAHoldersPausedStateIsReadBack(t *testing.T) {
t.Fatalf("read back %+v", said)
}
}
// A `build` waiting on its outcome hears a cancel — which publishes no outcome — from the cancelled
// set, and a kill from the outcome the holder announces (novox/hq ADR 0219).
func TestNatsAWaitingAskerHearsItsAskCancelledOrKilled(t *testing.T) {
js := aBusWithACancelledSet(t)
was := cancelLook
cancelLook = 200 * time.Millisecond
t.Cleanup(func() { cancelLook = was })
ask := &natsBuilds{js: js, seat: TheBuildMachine}
go func() {
time.Sleep(500 * time.Millisecond)
_ = MarkCancelled(context.Background(), js, TheBuildMachine, "build-waited-cancelled")
}()
result, err := ask.Submit(context.Background(), BuildRequest{ID: "build-waited-cancelled", Repository: "/r"}, 10*time.Second)
if err != nil || result.Failed != CancelledByHand || result.ID != "build-waited-cancelled" {
t.Fatalf("the waiter heard %+v (%v)", result, err)
}
// Killed: the holder announces the failure as any outcome, and the waiter has it.
ctx, stop := context.WithCancel(context.Background())
defer stop()
machine := MachineOverNATS(js, "ace")
defer machine.Close()
go func() {
_ = machine.Take(ctx, func(ctx context.Context, work Build) {
r := work.Request()
_ = work.Announce(ctx, BuildResult{ID: r.ID, Repository: r.Repository, On: "ace", Failed: KilledByHand})
_ = work.Done()
})
}()
result, err = ask.Submit(context.Background(), BuildRequest{ID: "build-waited-killed", Repository: "/r"}, 10*time.Second)
if err != nil || result.Failed != KilledByHand || result.On != "ace" {
t.Fatalf("the waiter heard %+v (%v)", result, err)
}
}