Wait out a bus that answers nothing for a few seconds instead of losing the write (issue 774)

At each mesh-grants restart and user-list reload (16:37:24, 16:55:15) nats-server 2.11's reloadAuthorization left
the mesh's account without its imports, $JS.API.> among them, for a few seconds: requests had no responders,
JetStream calls said it was not enabled, and a build-test result on ace was lost.

Quick fix, chosen as asked; the thorough fix is a reload that keeps the account's imports, in the bus's holder.
The package busretry asks a request again, backing off within about 30 s, only while its error says it reached no
one (no responders, JetStream not enabled, no response from the stream, or either in words): nothing was done, so
even a create or an update is safe to ask again. A timeout or any answer is never asked again. After the bound it
is said on standard error and returned. Used by process.State's requests, process.Conn's calls (asked again only
while $JS.API.INFO says the bus itself answers nothing, so a callee that is not running still fails at once) and
asks, and the bundle's state requests through the runtime.
This commit is contained in:
2026-10-30 18:18:32 +01:00
parent 1dc5d8cb3d
commit 44dbb22ea7
7 changed files with 211 additions and 8 deletions
+14
View File
@@ -13,6 +13,7 @@ import (
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/asker"
"git.novox.be/novox/mesh-sdk/go/busretry"
)
// fakeEntry is a fakeKV's KeyValueEntry: only Key, Value and Revision are read by State.
@@ -206,6 +207,19 @@ func TestStatePutWritesAKeyWhole(t *testing.T) {
if err != nil || e == nil || e.Revision != rev2 || string(e.Value) != `{"a":2}` {
t.Fatalf("Get after Put: %+v, %v", e, err)
}
// Issue 774: a bus that answers nothing for a moment (a user-list reload) is waited out, not a lost write.
busretry.FirstWait = time.Millisecond
kv, blackedOut := newFakeKV(), 2
dark := State{Module: "mesh-mail", Name: "sends", kv: func(context.Context) (jetstream.KeyValue, error) {
if blackedOut > 0 {
blackedOut--
return nil, jetstream.ErrJetStreamNotEnabled
}
return kv, nil
}}
if rev, err := dark.Put("k", 1); err != nil || rev == 0 || blackedOut != 0 {
t.Fatalf("a Put through a short blackout: %d, %v", rev, err)
}
}
// 1840/S1: given a state, when its keys are listed, then they come sorted, and none is an empty list, not an error.