Bind the have bucket once per pass, bound by the queue's timeout, and stop the pass at the first error (issue 1132)

This commit is contained in:
2026-10-18 19:18:08 +02:00
parent 0b391f49a2
commit 9d9e3a46c4
4 changed files with 129 additions and 50 deletions
+31 -21
View File
@@ -118,24 +118,38 @@ func (b OverNATS) Alive(ctx context.Context, node string, body []byte) error {
return b.Conn.FlushWithContext(flush)
}
// haveBucket binds to the have bucket the controller made (novox/hq ADR 0429 §4, issue 1132). **Only binds**: a node-engine's
// account reaches no part of the JetStream API beyond what it is granted, and the bucket is the controller's to create
// and to configure, so a bucket that is not there is an error said as what it is.
func (b OverNATS) haveBucket() (nats.KeyValue, error) {
kv, err := b.JS.KeyValue(delivery.HaveBucket)
// HaveBind binds the have bucket the controller made (novox/hq ADR 0429 §4, issue 1132), once for a pass of writes.
// **Only binds**: a node-engine's account reaches no part of the JetStream API beyond what it is granted, and the bucket
// is the controller's to create and to configure, so a bucket that is not there is an error said as what it is. Every
// call on the bucket waits no longer than ctx has left: a refused publish is answered by nothing, and the client's own
// wait is five seconds.
func (b OverNATS) HaveBind(ctx context.Context) (HaveBucket, error) {
js := b.JS
wait := 5 * time.Second
if at, ok := ctx.Deadline(); ok {
wait = time.Until(at)
if wait <= 0 {
return nil, context.DeadlineExceeded
}
}
if b.Conn != nil {
bounded, err := b.Conn.JetStream(nats.MaxWait(wait))
if err != nil {
return nil, err
}
js = bounded
}
kv, err := js.KeyValue(delivery.HaveBucket)
if err != nil {
return nil, fmt.Errorf("the have bucket %s: %w", delivery.HaveBucket, err)
}
return kv, nil
return natsHaveBucket{kv}, nil
}
// HaveGet reads a key of the have bucket with its revision.
func (b OverNATS) HaveGet(_ context.Context, key string) ([]byte, uint64, error) {
kv, err := b.haveBucket()
if err != nil {
return nil, 0, err
}
entry, err := kv.Get(key)
type natsHaveBucket struct{ kv nats.KeyValue }
func (n natsHaveBucket) Get(_ context.Context, key string) ([]byte, uint64, error) {
entry, err := n.kv.Get(key)
if errors.Is(err, nats.ErrKeyNotFound) {
return nil, 0, ErrHaveAbsent
}
@@ -145,17 +159,13 @@ func (b OverNATS) HaveGet(_ context.Context, key string) ([]byte, uint64, error)
return entry.Value(), entry.Revision(), nil
}
// HaveSet writes a key of the have bucket over the revision read, or creates it when the revision is zero.
func (b OverNATS) HaveSet(_ context.Context, key string, value []byte, revision uint64) error {
kv, err := b.haveBucket()
if err != nil {
return err
}
func (n natsHaveBucket) Set(_ context.Context, key string, value []byte, revision uint64) error {
var err error
if revision == 0 {
_, err = kv.Create(key, value)
_, err = n.kv.Create(key, value)
return err
}
_, err = kv.Update(key, value, revision)
_, err = n.kv.Update(key, value, revision)
return err
}