G-delivery 7: the indexer's and the assigner's views emitters write view-unsaid
mesh-sdk's views.Emitter writes the owner's finding of a change not said past its bound only when Findings is set; both owners of views in mesh-delivery now set it to their findings state. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -21,11 +21,17 @@ import (
|
||||
oc "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
)
|
||||
|
||||
// 1297/B2a: the buckets the program opens are exactly the manifest's reads and states, as the broker names them
|
||||
// (`<module>.<state>` read as the bucket `<module>_<state>`), so it is granted what it reads and reads nothing else.
|
||||
func TestOpensWhatItsManifestNames(t *testing.T) {
|
||||
// Review round 2: the assigner's views emitter writes its finding view-unsaid (Emitter.Findings set) when it keeps findings.
|
||||
findings := assign.Findings{Put: func(string, []byte) error { return nil }, Delete: func(string) error { return nil }}
|
||||
if viewsEmitter(nil, process.Account{}, nil, findings, nil, t.Logf).Findings == nil {
|
||||
t.Error("the assigner's views emitter writes no view-unsaid finding")
|
||||
}
|
||||
// 1297/B2a: without a credential the program does not start, and says why.
|
||||
if err := run(context.Background(), func(string) string { return "" }, io.Discard); err == nil || !strings.Contains(err.Error(), "MESH_BROKER_FILE") {
|
||||
t.Errorf("run without a credential = %v", err)
|
||||
|
||||
@@ -98,7 +98,7 @@ func startViews(ctx context.Context, js jetstream.JetStream, nc process.Subscrib
|
||||
}
|
||||
}
|
||||
process.AwaitBucket(ctx, js, nc, marksBucket, "no change is said on the views family, so every reader waits on its first view", logf).Ready(func(mk jetstream.KeyValue) {
|
||||
em := views.Emitter{Owner: delivery.AssignerModule, Subject: account.StreamSubject, Publish: views.JetStreamPublish(js), Marks: mk, TooLarge: tooLarge, Logf: logf}
|
||||
em := viewsEmitter(js, account, mk, findings, tooLarge, logf)
|
||||
for _, state := range []string{"asks", "differences", health.FindingsState, delivery.PlacementState, delivery.SeatHoldersState, "wants"} {
|
||||
state := state
|
||||
start := func(kv jetstream.KeyValue) {
|
||||
@@ -115,6 +115,22 @@ func startViews(ctx context.Context, js jetstream.JetStream, nc process.Subscrib
|
||||
})
|
||||
}
|
||||
|
||||
// viewsEmitter is the assigner's emitter of its views family: a change not said past views.Bound is its finding
|
||||
// view-unsaid, in its findings (review round 2); with no findings state it is said in the log only.
|
||||
func viewsEmitter(js jetstream.JetStream, account process.Account, mk jetstream.KeyValue, findings assign.Findings, tooLarge func(string, string, int), logf func(string, ...any)) views.Emitter {
|
||||
em := views.Emitter{Owner: delivery.AssignerModule, Subject: account.StreamSubject, Publish: views.JetStreamPublish(js), Marks: mk, TooLarge: tooLarge, Logf: logf}
|
||||
if findings.Put != nil && findings.Delete != nil {
|
||||
em.Findings = assignerFindings{findings}
|
||||
}
|
||||
return em
|
||||
}
|
||||
|
||||
// assignerFindings is the assigner's findings as views.Emitter's Findings.
|
||||
type assignerFindings struct{ f assign.Findings }
|
||||
|
||||
func (a assignerFindings) Put(key string, value []byte) error { return a.f.Put(key, value) }
|
||||
func (a assignerFindings) Delete(key string) error { return a.f.Delete(key) }
|
||||
|
||||
// firstViewsBucket is the assigner's own state of its first views (views.StatusState).
|
||||
var firstViewsBucket = delivery.AssignerModule + "_" + views.StatusState
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
|
||||
"mesh-delivery-indexer/internal/index"
|
||||
)
|
||||
@@ -71,6 +72,10 @@ func (m *memStore) Delete(_ context.Context, k string, _ uint64) error { delete(
|
||||
const head = "0123456789abcdef0123456789abcdef01234567"
|
||||
|
||||
func TestAMessageIsIndexedAndAcked(t *testing.T) { // 1238/AC2 (unit part)
|
||||
// Review round 2: the indexer's views emitter writes its finding view-unsaid (Emitter.Findings set).
|
||||
if em := viewsEmitter(context.Background(), nil, process.Account{}, nil, &process.AwaitedBucket{}, nil, t.Logf); em.Findings == nil {
|
||||
t.Error("the indexer's views emitter writes no view-unsaid finding")
|
||||
}
|
||||
t.Run("not a forge message: terminated and logged", func(t *testing.T) { // 1238 (never redelivered)
|
||||
var logs bytes.Buffer
|
||||
st := &memStore{vals: map[string][]byte{}}
|
||||
|
||||
@@ -47,8 +47,7 @@ func startViews(ctx context.Context, js jetstream.JetStream, cred process.Accoun
|
||||
}
|
||||
}
|
||||
marks.Ready(func(mk jetstream.KeyValue) {
|
||||
em := views.Emitter{Owner: delivery.IndexerModule, Subject: cred.StreamSubject, Publish: views.JetStreamPublish(js),
|
||||
Marks: mk, TooLarge: tooLarge, Logf: logf}
|
||||
em := viewsEmitter(ctx, js, cred, mk, findings, tooLarge, logf)
|
||||
for _, state := range sortedStates(states) {
|
||||
states[state](func(kv jetstream.KeyValue) {
|
||||
if err := em.Start(ctx, state, kv, errs); err != nil {
|
||||
@@ -59,6 +58,24 @@ func startViews(ctx context.Context, js jetstream.JetStream, cred process.Accoun
|
||||
})
|
||||
}
|
||||
|
||||
// viewsEmitter is the indexer's emitter of its views family: a change not said past views.Bound is its finding
|
||||
// view-unsaid, in its own findings once bound (review round 2).
|
||||
func viewsEmitter(ctx context.Context, js jetstream.JetStream, cred process.Account, mk jetstream.KeyValue, findings *process.AwaitedBucket,
|
||||
tooLarge func(string, string, int), logf func(string, ...any)) views.Emitter {
|
||||
w := notHeardWriter(ctx, findings, logf)
|
||||
return views.Emitter{Owner: delivery.IndexerModule, Subject: cred.StreamSubject, Publish: views.JetStreamPublish(js),
|
||||
Marks: mk, TooLarge: tooLarge, Findings: funcFindings{put: w.Put, del: w.Delete}, Logf: logf}
|
||||
}
|
||||
|
||||
// funcFindings is a findings state as two functions: views.Emitter's Findings.
|
||||
type funcFindings struct {
|
||||
put func(string, []byte) error
|
||||
del func(string) error
|
||||
}
|
||||
|
||||
func (f funcFindings) Put(key string, value []byte) error { return f.put(key, value) }
|
||||
func (f funcFindings) Delete(key string) error { return f.del(key) }
|
||||
|
||||
func sortedStates(states map[string]readyOf) []string {
|
||||
out := make([]string, 0, len(states))
|
||||
for s := range states {
|
||||
|
||||
Reference in New Issue
Block a user