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:
@@ -106,7 +106,20 @@ func (b *natsBuilds) Submit(ctx context.Context, request BuildRequest,
|
||||
waiting, cancelWait := context.WithTimeout(ctx, wait)
|
||||
defer cancelWait()
|
||||
for {
|
||||
msg, err := outcomes.NextMsgWithContext(waiting)
|
||||
// **A wait that hears a cancel** (novox/hq ADR 0219). A person cancelling an ask records its
|
||||
// failure without publishing the role's outcome — that subject is the holders', and the
|
||||
// controller may not speak for them — so the waiter also looks, every while, at the cancelled
|
||||
// set the cancel wrote first. A kill needs no look: the holder announces it as any outcome.
|
||||
slice, endSlice := context.WithTimeout(waiting, cancelLook)
|
||||
msg, err := outcomes.NextMsgWithContext(slice)
|
||||
endSlice()
|
||||
if errors.Is(err, context.DeadlineExceeded) && waiting.Err() == nil {
|
||||
if cancelled, _ := IsCancelled(b.js.Conn(), b.role(), request.ID); cancelled {
|
||||
return BuildResult{ID: request.ID, Repository: request.Repository, Path: request.Path,
|
||||
Ref: request.Ref, Source: request.Source, DryRun: request.DryRun, Failed: CancelledByHand}, nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case errors.Is(err, context.DeadlineExceeded):
|
||||
return BuildResult{}, waitingFor(wait)
|
||||
@@ -125,6 +138,9 @@ func (b *natsBuilds) Submit(ctx context.Context, request BuildRequest,
|
||||
}
|
||||
}
|
||||
|
||||
// cancelLook is how often a waiting asker looks whether its ask was cancelled.
|
||||
var cancelLook = 2 * time.Second
|
||||
|
||||
// --- the machine's side ---------------------------------------------------------------------
|
||||
|
||||
type natsMachine struct {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user