From cde060d5230b67f61fb5d1ef77034a1930ef4302 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:12:49 +0100 Subject: [PATCH] =?UTF-8?q?Checker:=20reads=20the=20seat=20list=20when=20i?= =?UTF-8?q?ts=20hub=20is=20heard=20while=20it=20is=20unread,=20since=20the?= =?UTF-8?q?=20seat's=20event=20before=20its=20consumer=20is=20lost=20to=20?= =?UTF-8?q?it=20(ADR=200636=20=C2=A71;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/mesh-delivery-checker/main.go | 2 + .../cmd/mesh-delivery-checker/seatlist.go | 10 +++++ .../mesh-delivery-checker/seatlist_test.go | 41 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go index 55a908d7..c819ad4b 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go @@ -465,6 +465,8 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro // check fails at its publish bound until the checker starts again. if err := hub.Start(ctx, js, cred); err != nil { logger.Printf("%v, so no package registry's published is heard and a group's check fails at its publish bound until the checker starts again", err) + } else { + readIfUnread(seats.reader) } defer hub.Stop() // The checks, the tries and the hand asks, once every first view is answered (the lead's ruling for DLV-M2): a check diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist.go index 6da7f71e..313d2d6d 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist.go @@ -49,3 +49,13 @@ func (s seatList) Definitions() ([]json.RawMessage, error) { } return out, nil } + +// readIfUnread is called when the checker's hub is heard. The seat may have answered, and said that it does, before the +// checker's consumer existed, whose events start at the stream's end: the first read found it silent and nothing else reads +// again until its next event, so while the list is unread it is read now, on a goroutine of its own (ADR 0636 §1). +func readIfUnread(reader *seatlist.Reader) { + if reader == nil || reader.Status().Heard { + return + } + go func() { _ = reader.Reload() }() +} diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go new file mode 100644 index 00000000..8ae0bda4 --- /dev/null +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go @@ -0,0 +1,41 @@ +package main + +import ( + "encoding/json" + "errors" + "sync/atomic" + "testing" + "time" + + "git.novox.be/novox/mesh-sdk/go/seatlist" +) + +// silentThenAnswering is a seat that is silent at the reader's first read and answers after. +type silentThenAnswering struct{ answering atomic.Bool } + +func (b *silentThenAnswering) Ask(string, any) (json.RawMessage, error) { + if !b.answering.Load() { + return nil, errors.New("not connected yet") + } + return json.RawMessage(`{"revision":1,"seats":[]}`), nil +} + +func (b *silentThenAnswering) Subscribe(string, func(string, json.RawMessage) error) error { return nil } + +// A seat that spoke before the checker's consumer existed is read when the hub is heard (ADR 0636 §1). +func TestTheSeatListIsReadWhenTheHubIsHeard(t *testing.T) { + bus := &silentThenAnswering{} + reader := followSeatList(bus, t.Logf) + <-reader.Ready() + if reader.Status().Heard { + t.Fatal("a silent seat was heard") + } + bus.answering.Store(true) + readIfUnread(reader) + for deadline := time.Now().Add(5 * time.Second); !reader.Status().Heard; time.Sleep(10 * time.Millisecond) { + if time.Now().After(deadline) { + t.Fatal("the list was not read when the hub was heard") + } + } + var _ seatlist.Bus = bus +}