Read the router's ask ids without taking a second stop of the key lister for a failure (issue 1336)
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/asks"
|
||||
@@ -267,6 +268,11 @@ var routerAskIDs = func(ctx context.Context, inv catalogueReader, asker string)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return askIDsOf(ctx, kv, asker)
|
||||
}
|
||||
|
||||
// askIDsOf are the ids of the asks an asker has in the router's bucket.
|
||||
func askIDsOf(ctx context.Context, kv jetstream.KeyValue, asker string) ([]string, error) {
|
||||
lister, err := kv.ListKeysFiltered(ctx, asker+".>")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -275,7 +281,9 @@ var routerAskIDs = func(ctx context.Context, inv catalogueReader, asker string)
|
||||
for key := range lister.Keys() {
|
||||
ids = append(ids, strings.TrimPrefix(key, asker+"."))
|
||||
}
|
||||
if err := lister.Stop(); err != nil {
|
||||
// The lister stops its own watch when it has sent the last key, so a stop of ours finds it stopped: nats answers that with
|
||||
// "invalid subscription", which is no failure of the read (issue 1336). Any other error stays one.
|
||||
if err := lister.Stop(); err != nil && !errors.Is(err, nats.ErrBadSubscription) {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
//go:build integration
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/testbus"
|
||||
)
|
||||
|
||||
// Issue 1336: the catch-up lists the ids of an asker's asks in the router's bucket. The key lister stops its own watch when the last
|
||||
// key is read, and a second stop answers "nats: invalid subscription"; read as a failure, it made every warrant unreadable on novox
|
||||
// (2026-10-20, 110 gaps named, none planned).
|
||||
func TestTheAskIDsOfAnAskerAreReadFromTheRoutersBucketWithoutAFalseFailure(t *testing.T) {
|
||||
conn, err := nats.Connect(testbus.URL(t))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(conn.Close)
|
||||
js, err := jetstream.New(conn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx := t.Context()
|
||||
kv, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: "router_asks_test"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = js.DeleteKeyValue(context.Background(), "router_asks_test") })
|
||||
for _, key := range []string{"mesh-delivery.merge-378-b9104454f9a5-1", "mesh-delivery.merge-377-aaaaaaaaaaaa-1",
|
||||
"mesh-delivery-teller.merge-feat_r4b_sdk_users-ba59b03220f8-989afe0a3bcf", "keycloak.something"} {
|
||||
if _, err := kv.Put(ctx, key, []byte(`{}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
got, err := askIDsOf(ctx, kv, "mesh-delivery")
|
||||
if err != nil {
|
||||
t.Fatalf("the ids of an asker's asks could not be read: %v", err)
|
||||
}
|
||||
slices.Sort(got)
|
||||
if want := []string{"merge-377-aaaaaaaaaaaa-1", "merge-378-b9104454f9a5-1"}; !slices.Equal(got, want) {
|
||||
t.Fatalf("read %v, want %v: the teller's and another module's asks are not mesh-delivery's", got, want)
|
||||
}
|
||||
if none, err := askIDsOf(ctx, kv, "nobody"); err != nil || len(none) != 0 {
|
||||
t.Fatalf("an asker with no asks read as %v, %v", none, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user