Stop declaring and reading the ASSIGNMENTS stream: a runtime reads its membership from the grants part's state, and the stream is deleted at the lease write and must not be made again (issue 774, research 072 row 33)
This commit is contained in:
+34
-16
@@ -1,24 +1,26 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/membership"
|
||||
)
|
||||
|
||||
// FollowMembership reads this account's own membership and follows it (novox/hq ADR 0160): apply is called
|
||||
// with every membership the mesh issues this account's node and module, the one already issued first and
|
||||
// each later one as it is published, so a change reaches a running process without a restart. A body that is
|
||||
// each later one as it is issued, so a change reaches a running process without a restart. A body that is
|
||||
// not a membership is handed to onBad (nil to ignore it) and skipped.
|
||||
//
|
||||
// The subject is followed before it is read, so an issue landing between the two is applied, not missed. The
|
||||
// read is the subject-addressed direct get, the one request this account may make of the stream; no
|
||||
// membership issued yet, or the read failing, is not an error: the process follows the subject and is told
|
||||
// when one arrives. The returned error is a refusal to follow at all.
|
||||
// It reads the membership from the grants part's state memberships, its own key (novox/hq ADR 0571 clause 7),
|
||||
// watched so the value there now comes first and each change after it; and it hears the subject the grants part
|
||||
// publishes on until the lease write. The assignments stream is no longer read: the bus module's tools delete it
|
||||
// at the lease write (research 072 row 33). A state not there yet, or not readable, is told to onBad and the
|
||||
// subject is followed alone. The returned error is a refusal to follow at all.
|
||||
func (c *Conn) FollowMembership(apply func(membership.Membership), onBad func(error)) error {
|
||||
if c.account.Node == "" || c.account.Module == "" {
|
||||
return fmt.Errorf("the account names no node or module, so it has no membership")
|
||||
@@ -29,8 +31,8 @@ func (c *Conn) FollowMembership(apply func(membership.Membership), onBad func(er
|
||||
}
|
||||
}
|
||||
take := func(body []byte) {
|
||||
var issued membership.Membership
|
||||
if err := json.Unmarshal(body, &issued); err != nil {
|
||||
issued, err := membership.DecodeGrantsMembership(body)
|
||||
if err != nil {
|
||||
bad(fmt.Errorf("a membership arrived that is not one: %w", err))
|
||||
return
|
||||
}
|
||||
@@ -40,14 +42,30 @@ func (c *Conn) FollowMembership(apply func(membership.Membership), onBad func(er
|
||||
if _, err := c.nc.Subscribe(subject, func(m *nats.Msg) { take(m.Data) }); err != nil {
|
||||
return fmt.Errorf("cannot follow %s: %w", subject, err)
|
||||
}
|
||||
got, err := c.nc.Request(membership.DirectGetSubject(c.account.Node, c.account.Module), nil, 5*time.Second)
|
||||
switch {
|
||||
case err != nil:
|
||||
bad(fmt.Errorf("cannot read the membership issued on %s yet (%v); following it", subject, err))
|
||||
case got.Header.Get("Status") != "" || len(got.Data) == 0:
|
||||
// None issued yet: the follow above delivers it.
|
||||
default:
|
||||
take(got.Data)
|
||||
key := membership.GrantsKey(c.account.Node, c.account.Module)
|
||||
js, err := jetstream.New(c.nc)
|
||||
if err != nil {
|
||||
bad(fmt.Errorf("cannot read %s of %s (%v); following %s alone", key, membership.GrantsBucket, err, subject))
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
kv, err := js.KeyValue(ctx, membership.GrantsBucket)
|
||||
if err != nil {
|
||||
bad(fmt.Errorf("cannot read %s of %s yet (%v); following %s alone", key, membership.GrantsBucket, err, subject))
|
||||
return nil
|
||||
}
|
||||
w, err := kv.Watch(context.Background(), key)
|
||||
if err != nil {
|
||||
bad(fmt.Errorf("cannot watch %s of %s (%v); following %s alone", key, membership.GrantsBucket, err, subject))
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
for e := range w.Updates() {
|
||||
if e != nil && e.Operation() == jetstream.KeyValuePut {
|
||||
take(e.Value())
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user