|
|
|
@@ -30,19 +30,37 @@ Prose and diagrams only; no configuration is pasted.
|
|
|
|
|
|
|
|
|
|
## 1. What the bus is for
|
|
|
|
|
|
|
|
|
|
The bus carries five kinds of traffic today, and this design keeps the five, renaming nothing a
|
|
|
|
|
module can see:
|
|
|
|
|
**The bus is where the mesh happens.** Not a transport the mesh sends things over — the place a
|
|
|
|
|
module is reachable at all, where a role is addressed without knowing who holds it, where the
|
|
|
|
|
mesh's own state lives, and where what a module may say is decided by what it declared.
|
|
|
|
|
|
|
|
|
|
| Traffic | Today | Guarantee it needs |
|
|
|
|
|
| Traffic | Shape | Guarantee it needs |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
| **control** — a node's report, its heartbeat, a build's outcome, an enrolment | queues `control`, `.upgrades`, `.catchup` | nothing lost while the store restarts; retried; in order per node |
|
|
|
|
|
| **declarations** — the controller tells a node what to be | queue `node.<name>` | the node gets the newest; a stale one is never applied |
|
|
|
|
|
| **builds** — the controller asks the build machine to build | queue `builds` | at least once, one builder at a time |
|
|
|
|
|
| **events** — a module says something happened | topic exchange `mesh.events`, keys `<module>.<event>` | delivered to every consumer that declared it; dead-lettered when it cannot be |
|
|
|
|
|
| **tools** — one module or person asks another's tool a question | exchange `mesh.rpc`, per-tool service queues `serve.<module>.<tool>` | one answer, from one server, or a timeout |
|
|
|
|
|
| **control** — a node's report, a build's outcome, an enrolment | job | nothing lost while the store restarts; retried; in order per node |
|
|
|
|
|
| **heartbeat** — a node saying it is alive | fire and forget | none; a lost one is the next one |
|
|
|
|
|
| **declarations** — the controller tells a node what to be | state | the node gets the newest; a stale one is never applied |
|
|
|
|
|
| **builds** — work for the build machine | job | at least once, one worker at a time |
|
|
|
|
|
| **events** — a module says something happened | 1:many | delivered to every consumer that declared it; dead-lettered when it cannot be |
|
|
|
|
|
| **tools** — a module or a person asks another's tool | request/reply | one answer, from one server, or a timeout |
|
|
|
|
|
| **work to a role** — a module submits to a capability without knowing who provides it | job | exactly one holder does it; it queues while nobody does |
|
|
|
|
|
|
|
|
|
|
The sdk's contract — `request`, `handle`, `publish`, `subscribe`, `close` — is the whole surface a
|
|
|
|
|
module sees, and it does not change ([ADR 0039](../../02-DECISIONS/0039-what-the-sdk-holds-and-refuses.md)).
|
|
|
|
|
The last two rows are the ones worth dwelling on, because they are not messaging in the sense of
|
|
|
|
|
carrying bytes from A to B. **A role is addressable**, so a caller names the capability and never
|
|
|
|
|
the module or the node — and the implementation can be replaced under it without a caller
|
|
|
|
|
changing ([ADR 0118](../../02-DECISIONS/0118-a-module-declares-its-own-seats.md)). That is a
|
|
|
|
|
property of the mesh's architecture that happens to be expressed in subjects.
|
|
|
|
|
|
|
|
|
|
And more of the mesh lands here as it is built: conditions and observed state in key-value
|
|
|
|
|
buckets that anything may watch, the server's own advisories becoming observations like any other
|
|
|
|
|
([research 017](../../01-RESEARCH/017-a-mesh-that-heals-itself/00-overview.md)), and a person's
|
|
|
|
|
client speaking the bus directly rather than through a surface built over it (§7). None of that
|
|
|
|
|
is a message being moved; all of it is the bus being the mesh's centre.
|
|
|
|
|
|
|
|
|
|
**What a module sees of it is small and derived.** It declares what it emits, consumes, serves
|
|
|
|
|
and uses, and the subjects, streams, consumers and permissions all follow from that
|
|
|
|
|
([design 29](29-what-a-module-declares.md)). The sdk's contract — `request`, `handle`, `publish`,
|
|
|
|
|
`subscribe`, `close` — is the whole surface, and it does not change
|
|
|
|
|
([ADR 0039](../../02-DECISIONS/0039-what-the-sdk-holds-and-refuses.md)).
|
|
|
|
|
|
|
|
|
|
## 2. Subjects
|
|
|
|
|
|
|
|
|
@@ -212,11 +230,11 @@ same place `modules/gitea/token.ts` keeps its own state rather than asking the h
|
|
|
|
|
The host's only job is what it already does for any directory resource: keep the file's content
|
|
|
|
|
current. Nothing is declared as `reload-on` or `restart-on` for this resource at all.
|
|
|
|
|
|
|
|
|
|
Its guard is the same rule as the AMQP broker's: the monitoring port is refused from anything but
|
|
|
|
|
Its guard is the same rule as the deprecated broker's: the monitoring port is refused from anything but
|
|
|
|
|
the private network. It is raised at genesis like the store, adopted as a module in the same
|
|
|
|
|
phase.
|
|
|
|
|
|
|
|
|
|
**The AMQP broker is an ordinary module, not a compatibility layer.** Revision, second review
|
|
|
|
|
**The deprecated broker is an ordinary module, not a compatibility layer.** Revision, second review
|
|
|
|
|
([ADR 0119](../../02-DECISIONS/0119-amqp-is-a-provision-not-the-bus.md)): earlier text here, and
|
|
|
|
|
ADR 0106 before it, called it `lavinmq-compat` — one purpose, the predecessor's clients, and a
|
|
|
|
|
retirement condition of no client connected for a period the operator sets. It is none of those.
|
|
|
|
@@ -231,17 +249,6 @@ that remains is about direction rather than software: *inter-module communicatio
|
|
|
|
|
bus.* A module may hold a broker, a database or a cache for itself; it may not use one as a
|
|
|
|
|
channel to another module.
|
|
|
|
|
|
|
|
|
|
**And with one purpose, which it did not have when this was written.** Revision, second review
|
|
|
|
|
([ADR 0119](../../02-DECISIONS/0119-amqp-is-a-provision-not-the-bus.md) (superseding [ADR 0117](../../02-DECISIONS/0117-the-bus-is-the-only-broker.md))): two modules of the new mesh
|
|
|
|
|
required a broker *of their own* from it — a private vhost per consumer, the analog of
|
|
|
|
|
database-per-login, which is a different thing from the mesh's bus and was never examined here.
|
|
|
|
|
**There is one bus, and no module is handed a broker as a resource.** A module's messaging is
|
|
|
|
|
subjects on the bus under its own account, scoped by its `emits` and `consumes`; a module that
|
|
|
|
|
wants a queue of its own has a subject nothing else may publish to and a durable consumer, both
|
|
|
|
|
from its declaration. What it does not get is a server of its own. The `amqp` interface retires
|
|
|
|
|
with the compatibility broker instead of gaining a successor, and the two modules move to the bus
|
|
|
|
|
in step 4.
|
|
|
|
|
|
|
|
|
|
## 6. Joining: the enrolment handshake
|
|
|
|
|
|
|
|
|
|
Unchanged in shape, changed in transport. A node that has a token connects to the bus over TLS
|
|
|
|
@@ -323,7 +330,7 @@ wrong until there is a second mesh. *Ends at: the genesis bed.*
|
|
|
|
|
**Step 2 — adoption puts the broker in its seat.** A mesh already running does not get a foundation
|
|
|
|
|
module by being raised again; it adopts one in place
|
|
|
|
|
([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)). The
|
|
|
|
|
server is raised beside the AMQP broker on its own ports, carrying no mesh traffic yet, and the
|
|
|
|
|
server is raised beside the deprecated broker on its own ports, carrying no mesh traffic yet, and the
|
|
|
|
|
`nats` module is adopted onto it. The seat it claims is **`mesh-broker`**, unchanged — the
|
|
|
|
|
foundation seats are named after the server's role rather than the product
|
|
|
|
|
([ADR 0079](../../02-DECISIONS/0079-the-foundation-seats-are-named-after-their-servers.md)) for
|
|
|
|
@@ -384,7 +391,7 @@ itself enforces and a plain client can therefore check:
|
|
|
|
|
watcher-poll interval, without a restart.
|
|
|
|
|
|
|
|
|
|
**Step 2 — the adoption bed**, a mesh already running that has never had this server:
|
|
|
|
|
- the server is raised beside the AMQP broker on its own ports and the `nats` module is adopted
|
|
|
|
|
- the server is raised beside the deprecated broker on its own ports and the `nats` module is adopted
|
|
|
|
|
onto it in place, holding the data and the configuration it was raised with;
|
|
|
|
|
- the seat it claims is `mesh-broker`, and a second assignment of it anywhere in the mesh is
|
|
|
|
|
refused at resolution — *one per mesh*, as ADR 0079 requires;
|
|
|
|
|