Building the bus: the decisions the work needed, and what it taught back #150
@@ -128,6 +128,33 @@ call is a timeout the caller already handles.
|
||||
Streams and consumers are objects the controller creates at genesis and asserts on start; a module
|
||||
declares nothing about them. The controller is the only writer of stream definitions.
|
||||
|
||||
### The store window, and what moving it into the server changes
|
||||
|
||||
The guarantee ([ADR 0083](../../02-DECISIONS/0083-one-push-leaves-the-mesh-consistent.md)) is
|
||||
that a push the controller cannot record because its store is restarting is **held and retried** —
|
||||
never dropped, never falsely acknowledged. Here that is a `nak` with a delay: the server holds
|
||||
the message and redelivers it, so the controller keeps no list of parked messages and one that
|
||||
restarts mid-window loses nothing it was holding.
|
||||
|
||||
**That is a plain win, and it introduces one problem worth naming.** Holding a delivery in memory
|
||||
let the controller drop an older report when a newer one for the same node arrived, because
|
||||
acting on the older after the newer would undo the newer. A `nak`ed message belongs to the server
|
||||
and comes back whatever happened meanwhile — so the older report is redelivered *after* the newer
|
||||
was applied.
|
||||
|
||||
The answer was already in the message. A report carries the **digest of the declaration it is
|
||||
about**, which exists because an earlier attempt to order reports by time lost the race it
|
||||
invited: an apply that began under the previous declaration finishes after the next is sent, and
|
||||
its report reads as newer than the send. Clocks cannot answer *which*.
|
||||
|
||||
So supersession stops being something the controller remembers and becomes something it checks —
|
||||
a report whose digest is not the one outstanding for that node is acknowledged without being
|
||||
acted on. The same shape as a node refusing a superseded declaration by sequence
|
||||
([issue 107](../../04-ISSUES/107-a-declaration-carries-no-order/00-report.md)): **ordering settled
|
||||
by what a message says, not by when it arrived.** And staleness is checked before the store is
|
||||
waited on, so a redelivery that lost its race does not hold a slot in the window that a current
|
||||
message needs.
|
||||
|
||||
## 4. Accounts
|
||||
|
||||
[ADR 0043](../../02-DECISIONS/0043-a-module-broker-account-is-scoped-by-emits-and-consumes.md) says a
|
||||
|
||||
@@ -250,8 +250,17 @@ pays for itself furthest away.
|
||||
rather than from the code that wrote it.
|
||||
|
||||
The seam turned out to be eight call sites — the same smallness that said this bus could be
|
||||
replaced at all. Still on `*amqp.Channel`: `RequestBuild` and `Ask`, which carry reply-queue
|
||||
machinery, and the whole consume side (the control loop, enrolment, serving).
|
||||
replaced at all.
|
||||
|
||||
**The consume side's hard part is decided and tested**: the store window is a `nak` with a
|
||||
delay rather than a delivery held in memory, which also means a controller restarting
|
||||
mid-window loses nothing. Moving the holding into the server costs one thing — an older
|
||||
report is redelivered after a newer was applied — and a report already carries the digest
|
||||
of the declaration it is about, so supersession becomes a check rather than something the
|
||||
controller remembers. Pure and tested without a bus, a store or a clock.
|
||||
|
||||
Still outstanding: wiring that decision into the loop, `RequestBuild` and `Ask`, enrolment,
|
||||
and serving.
|
||||
- [~] 3.5 the host's link on NATS — **the outbound half is through a seam**, mirroring the
|
||||
controller's and still importing nothing of the mesh's own (ADR 0005): the host's own
|
||||
interface over its own libraries, agreeing with the controller only because a fixture holds
|
||||
|
||||
Reference in New Issue
Block a user