The tool runner reads the memberships state again until it can, instead of giving a module up at its one follow

A JetStream 503 or a timeout at the follow (a bus right after its boot) left the module with no membership for good, since
Follow runs once per module and the stream fallback is gone. The read is now tried again with a growing wait (1 s doubling
to 30 s) until it watches the key or the connection closes; the failure is said once, and its reading once it succeeds.
Tests: none added; a step added to an existing unit test (TestAModuleHearsEveryStreamItsMembershipNames), which fails
without the retry.

(issue 774, 774/S32, review g1 round 1)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 00:51:19 +01:00
parent 5b2ff5e321
commit 331fa06b54
3 changed files with 80 additions and 12 deletions
+23
View File
@@ -199,6 +199,29 @@ func TestAModuleHearsEveryStreamItsMembershipNames(t *testing.T) {
if got := consumerOf(); got != "from-grants-2" {
t.Fatalf("a membership said on the controller's subject was applied: the membership names %q", got)
}
// Review g1 round 1: memberships that cannot be read at the follow (a bus not ready after its boot) are read again until
// they can be; the follow, which runs once per module, does not give the module up for good.
was := bus.GrantsRetry
bus.GrantsRetry = 50 * time.Millisecond
t.Cleanup(func() { bus.GrantsRetry = was })
mesh.DropGrants(t)
late, err := bus.Connect(bus.Credential{URL: mt.URL(t), Module: "node-tools", Node: "anchor"})
if err != nil {
t.Fatal(err)
}
late.Logf = func(string, ...any) {}
t.Cleanup(late.Close)
late.Follow("reader")
if m := late.Membership("reader"); m != nil {
t.Fatalf("a membership was served from a state not there: %+v", m)
}
mesh.Issue(t, granted)
mt.Until(t, func() error {
if m := late.Membership("reader"); m == nil || len(m.Hears) != 1 || m.Hears[0].Consumer != "from-grants-2" {
return fmt.Errorf("the membership is %+v, want the one written once the state is there", m)
}
return nil
})
}
// novox/hq ADR 0363 §6 (issue 725): a consumer the membership names before the controller made it is bound once