The node answers a placement candidate revision once: a module's have whose health words alone moved, or a key written again with its value, no longer composes every group's answer again (issue 1126)
On shanks probe/1126-seed-7 was answered at revision 84 every 13-17 s: each look rewrote the haves of its unhealthy modules with new words, and the shadow took any write of its own module haves, placement, modules or config values as a change. Each answer loaded the bus, the health tools timed out, the words moved again. Now only what an answer is composed from wakes it (what runs, folded modules, a changed value), and each group is answered again only when its keys' revisions or the node's inputs moved.
This commit is contained in:
@@ -403,9 +403,67 @@ func TestNatsANodeThePlacementNamesComposesAndAppliesItsOwn(t *testing.T) {
|
||||
hkey, place, fp := st.hkey, st.place, st.fp
|
||||
within(t, 5*time.Second, "the node did not compose and apply its own module once placed", func() bool { return b.file("web") == "greeting=bonjour\n" })
|
||||
h8rest(t, b, resolved, candidates, hkey, place, fp)
|
||||
t.Run("one answer per candidate revision", func(t *testing.T) { h8once(t, b, resolved, candidates, place) })
|
||||
h8back(t, b, placement, resolved, candidates, hkey)
|
||||
}
|
||||
|
||||
// h8once is issue 1126, 2026-10-28 (shanks answered probe/1126-seed-7 at revision 84 every 13-17 s, its bus flooded):
|
||||
// a candidate revision is answered once. The node's own answer written, a module's have whose health words alone move
|
||||
// (each look rewrites them) and a config value written again with the value it held answer nothing again; the
|
||||
// candidate's next revision is answered once.
|
||||
func h8once(t *testing.T, b *itBed, resolved, candidates nats.KeyValue, place []byte) {
|
||||
answering := func() int {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
n := 0
|
||||
for _, l := range b.said {
|
||||
if strings.HasPrefix(l, "answering placement candidate feat/x ") {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
settled := answering()
|
||||
if settled == 0 {
|
||||
t.Fatal("feat/x was never answered")
|
||||
}
|
||||
hkey, _ := delivery.HaveKey(itNode, "web")
|
||||
for _, detail := range []string{"its tool web_health: no link to the bus is open", "its tool web_health: no answer within 10s"} {
|
||||
h := b.have("web")
|
||||
h.Health, h.Detail = delivery.HealthFailed, detail
|
||||
raw, err := delivery.EncodeHave(h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := b.haves.Put(hkey, raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := resolved.Put(itNode+".web.greeting", []byte(`{"value":"salut","source":"module"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
time.Sleep(1500 * time.Millisecond)
|
||||
if got := answering(); got != settled {
|
||||
t.Errorf("feat/x answered %d more time(s) at the same revision, with nothing it is composed from changed", got-settled)
|
||||
}
|
||||
same, _ := delivery.DecodePlacement(place)
|
||||
craw, err := delivery.EncodePlacementCandidate(delivery.PlacementCandidate{Group: "feat/x",
|
||||
Pull: delivery.Head{Repository: delivery.CatalogueRepository, Number: 1, Head: "h1b"}, Placement: &same})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ckey, _ := delivery.PlacementCandidateKey("feat/x", itNode)
|
||||
if _, err := candidates.Put(ckey, craw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
within(t, 10*time.Second, "the candidate's next revision was not answered", func() bool { return answering() > settled })
|
||||
time.Sleep(1500 * time.Millisecond)
|
||||
if got := answering(); got != settled+1 {
|
||||
t.Errorf("the candidate's next revision was answered %d time(s), want 1", got-settled)
|
||||
}
|
||||
}
|
||||
|
||||
// h8back is the way back (issue 1126, the seed's revert): a candidate deleting the node's placement is compared with
|
||||
// the controller's compositions at its wants (here none: refused, naming web), and the placement key deleted returns the agent to them without a
|
||||
// restart, said in the journal and the node's have, keeping what runs.
|
||||
|
||||
Reference in New Issue
Block a user