The mesh says what it applied, and the replay has an address it may use
The pipeline was observable from a merge to an artifact and went dark where it touched a machine: a node's report is control traffic only the control plane reads, so nothing said which version a machine runs, or that it refused to (novox/hq ADR 0134). The control plane now states both under the seat it holds — a role's events belong to the role and keep their address when the holder is replaced — and only when the report is news, because a machine reconciles every minute and a fact per report would be a fact per minute per machine. Whether a report is news is the store's answer: it holds the previous one, so the listener returns it and the server states the fact. That also gives the catch-up replay a subject the controller may publish: it was published as a module's event from a module called "control-plane", which does not exist, so the controller's own account refused it and every catalogue that asked what it missed was answered with nothing.
This commit is contained in:
@@ -30,6 +30,11 @@ type Bus interface {
|
||||
// (design 29 §4, the *state* shape).
|
||||
PublishDeclaration(ctx context.Context, node string, body []byte) error
|
||||
|
||||
// PublishSeatEvent states a fact under a role's own name, for the holder of that role. A
|
||||
// module's event is addressed to the module; a role's is addressed to the role, so it keeps
|
||||
// meaning when the holder changes (novox/hq ADR 0121, ADR 0129).
|
||||
PublishSeatEvent(ctx context.Context, seat, event string, body []byte) error
|
||||
|
||||
// AskTool sends one question to a module's tool and awaits one answer. A tool nobody serves
|
||||
// must say so **at once** rather than after the whole wait: the difference between "that
|
||||
// module is down" and "that tool is slow" is the first thing a person asking wants.
|
||||
@@ -81,6 +86,13 @@ func EventSubject(source, key string) string {
|
||||
return "mesh.mod." + source + ".event." + key
|
||||
}
|
||||
|
||||
// SeatEventSubject is where a role's own event lands. Derived from the role, never from its holder:
|
||||
// a fact about the build machine or about the control plane keeps its address when the module holding
|
||||
// that role is replaced (novox/hq ADR 0121, ADR 0129).
|
||||
func SeatEventSubject(seat, event string) string {
|
||||
return "mesh.seat." + seat + ".event." + event
|
||||
}
|
||||
|
||||
// DeclareSubject is where one node's declaration lands. Last-per-subject on the NODES stream, so
|
||||
// a node that was away gets exactly the current one and a replayed older one is refused by
|
||||
// sequence — the wire-level answer to novox/hq issue 107.
|
||||
@@ -112,6 +124,27 @@ func (b OverNATS) PublishEvent(ctx context.Context, key, source, node string, bo
|
||||
return nil
|
||||
}
|
||||
|
||||
// PublishSeatEvent states a role's own fact. Same envelope as a module's event and a different
|
||||
// address: the source header is the role, because that is what the fact is about.
|
||||
func (b OverNATS) PublishSeatEvent(ctx context.Context, seat, event string, body []byte) error {
|
||||
id, err := eventID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := nats.Header{}
|
||||
h.Set("x-event-id", id)
|
||||
h.Set("x-source", seat)
|
||||
_, err = b.JS.PublishMsg(&nats.Msg{
|
||||
Subject: SeatEventSubject(seat, event),
|
||||
Header: h,
|
||||
Data: body,
|
||||
}, nats.MsgId(id), nats.Context(ctx))
|
||||
if err != nil {
|
||||
return fmt.Errorf("stating %s of the %s seat: %w", event, seat, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b OverNATS) PublishDeclaration(ctx context.Context, node string, body []byte) error {
|
||||
_, err := b.JS.Publish(DeclareSubject(node), body, nats.Context(ctx))
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user