The runtime serves a list of modules on one credential, naming a bundle that fails to load (hq ADR 0175, to-be 38 WP1)
One tool runtime per node, host-side, is what the runtime was written to be; the catalogue built a container per module around it instead. This lets `serve` take a list — MESH_TOOL_MODULES as <module>=<entrypoint> entries — and do for every assigned module what it did for one: read that module's membership and follow it, serve its tools where the membership says, serve each held seat's verbs on the seat's subjects. The seats come from the memberships now, so the node's credential carries no claims; a module's own runtime still reads its credential's, so nothing built today changes behaviour. A bare path in MESH_TOOL_MODULES stays the one-module form. A bundle that throws on import is said in the log and in what `tools` answers for its module (`failed`), which discovery lists with the reason instead of as "not answering"; the other bundles serve. The filter that dropped every registration under a name but the one module goes; what stays is that a registration under a seat's name is served only where some served module claims the seat. A tool runs attributed to its module, so an event it emits lands on the module's subject and not the runtime's. MESH_OPERATOR_ACCOUNT and MESH_OPERATOR_HOME are read and said; tools take them from their environment. Proven against a real bus: three bundles, one broken; five tools and two seat verbs answer on their subjects; `tools` names the failed bundle; a membership re-issued mid-run re-serves.
This commit is contained in:
@@ -1,29 +1,42 @@
|
||||
# mesh-tools
|
||||
|
||||
The Novox Mesh **tool runtime** — the per-node process that makes a module's tools actually serve.
|
||||
The Novox Mesh **tool runtime** — the one process per node that makes every assigned module's tools
|
||||
actually serve (novox/hq ADR 0175).
|
||||
|
||||
A module ships its tools (built on [`@novox/mesh-sdk`](https://git.novox.be/novox/mesh-sdk)); this
|
||||
runtime is what loads them and puts them on the mesh. It:
|
||||
A module ships its tools as a bundle (built on [`@novox/mesh-sdk`](https://git.novox.be/novox/mesh-sdk));
|
||||
this runtime is what loads them and puts them on the mesh. It:
|
||||
|
||||
1. connects the mesh broker (novox/hq ADR 0001) — a concrete AMQP implementation of the sdk's
|
||||
`Broker` contract;
|
||||
2. imports the assigned modules' compiled tool entrypoints, each of which registers its tools as it
|
||||
loads;
|
||||
3. serves them through the sdk's `serveTools` harness, answering `tools.invoke` over the broker.
|
||||
1. connects the mesh bus on the node's credential — a concrete implementation of the sdk's `Broker`
|
||||
contract;
|
||||
2. reads one membership per module it serves — what the mesh issued that module on this machine
|
||||
(ADR 0160): where its tools are answered, which seats it holds — and follows each live;
|
||||
3. imports each module's compiled tool entrypoints, each of which registers its tools as it loads,
|
||||
guarded: a bundle that throws is named, in the log and in what `tools` answers for its module,
|
||||
and the others serve;
|
||||
4. serves every module's tools on that module's subjects and every held seat's verbs on the seat's.
|
||||
|
||||
Everything hard — dispatch, collection, duplicate-name safety — is the sdk's. This is the thin
|
||||
wrapper that binds the broker and loads the modules. Keeping the AMQP client here, out of the sdk,
|
||||
is deliberate: a broker-client change never rebuilds a module (ADR 0039).
|
||||
wrapper that binds the bus and loads the modules. Keeping the bus client here, out of the sdk, is
|
||||
deliberate: a bus-client change never rebuilds a module (ADR 0039). The runtime is module-agnostic:
|
||||
it knows bundles and subjects, nothing of what any module does. A tool that needs root escalates
|
||||
itself — root is the module's concern, not the runtime's.
|
||||
|
||||
## Running it
|
||||
|
||||
```
|
||||
MESH_BROKER_URL amqp://… the mesh broker
|
||||
MESH_TOOL_MODULES /a/tools/index.js,… the assigned modules' compiled tool entrypoints
|
||||
MESH_BROKER_FILE the node's sealed credential, as the mesh delivered it
|
||||
MESH_TOOL_MODULES alpha=/…/alpha/tools/index.js,beta=/…/beta/dist/index.js,…
|
||||
the modules to serve and their compiled entrypoints; several entries may
|
||||
name one module. A bare path is an entrypoint of the credential's own module
|
||||
— the one-module form a per-module container still sets.
|
||||
MESH_OPERATOR_ACCOUNT whose machine this is, and MESH_OPERATOR_HOME where their home is; set by
|
||||
the mesh when the node has an account, read by tools from their environment
|
||||
MESH_BROKER_URL a plain URL instead of the credential, for the bootstrap case
|
||||
```
|
||||
|
||||
`node dist/main.js`, or the container (`Dockerfile`). On a node the host resolves both variables
|
||||
and starts it like any other supervised workload.
|
||||
`node dist/main.js`. On a node the controller composes the variables and the host supervises the
|
||||
process like any other host-side workload (novox/hq to-be 38). The container (`Dockerfile`) is how
|
||||
a module's own *service* may still be built; it is no longer how tools reach a node.
|
||||
|
||||
## `mesh` — the tools for whoever is on a machine
|
||||
|
||||
@@ -41,6 +54,9 @@ dropped. A module may not name a tool of its own `tools`; the runtime refuses it
|
||||
|
||||
## Verified
|
||||
|
||||
`npm test` stands up LavinMQ (the mesh's broker) and proves the whole path over real AMQP: the
|
||||
runtime serves a registered tool, a separate connection invokes it by name and gets the result, and
|
||||
an unknown tool is refused over the wire.
|
||||
`npm test` runs against a real NATS server with JetStream (`MESH_TEST_NATS`, see any test's header
|
||||
for the one-line `docker run`) and proves the whole path over the wire: the runtime serves a
|
||||
registered tool, a separate connection invokes it by name and gets the result, an unknown tool is
|
||||
refused, a runtime serves exactly the subjects it is issued and re-serves on a new membership, and
|
||||
the node's runtime serves three modules' bundles on one credential — one of them broken, named and
|
||||
not fatal — with every seat verb answering where the membership put it.
|
||||
|
||||
Reference in New Issue
Block a user