docs(mesh): MeshTransport config, Phase 2 as shipped, design-doc correction
Rig: all six docker-dev nodes carry MeshTransport__Mode plus both central
contact points. Mode is "${OTOPCUA_MESH_MODE:-Dps}", so the rig still comes up
on the transport it has always used and the live gate can flip the whole fleet
at `docker compose up` without a compose edit or a rebuild.
Docs: a MeshTransport section in Configuration.md (including why contact points
are addresses only, why the contact set does not scope delivery, and why
buffer-size=0 is a behaviour decision rather than a tuning knob), a "Command
transport" section in Redundancy.md contrasting the two modes, and a summary
beside the Redundancy notes in CLAUDE.md.
Corrects the design doc's claim that ScadaBridge replies with a typed failure to
every unhandled message. Neither of their comm actors has a ReceiveAny or an
Unhandled override; the idiom is per message type and fires on a missing
registration, and an unknown type dead-letters there as it does anywhere else.
Records the exit-gate deviation in the program plan: "an Ask timing out cleanly
against a stopped node" cannot be run, because no Ask crosses this boundary. The
honest equivalents are a stopped node failing the deploy at the apply deadline
and an unreachable contact dropping the command with a Warning.
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -407,6 +407,37 @@ Net effect: each alarm transition appears **once** on `/alerts` and would histor
|
||||
|
||||
See [ScriptedAlarms.md](ScriptedAlarms.md) and [AlarmTracking.md](AlarmTracking.md) for the scripted-alarm engine internals.
|
||||
|
||||
## Command transport (central↔node)
|
||||
|
||||
Everything above rides one Akka mesh: central publishes on DistributedPubSub, every node
|
||||
subscribes, and the two ends must be members of the same cluster. Per-cluster mesh **Phase 2**
|
||||
adds a second transport under `MeshTransport:Mode` (see
|
||||
[Configuration.md § `MeshTransport`](Configuration.md#meshtransport-centralnode-command-transport))
|
||||
that does not need shared membership — the prerequisite for splitting the fleet into one mesh per
|
||||
application `Cluster`.
|
||||
|
||||
| | `Dps` (default) | `ClusterClient` |
|
||||
|---|---|---|
|
||||
| Central → node commands | `Publish` on `deployments` / `driver-control` / `alarm-commands` | `ClusterClient.SendToAll` to `/user/node-communication`, re-emitted on the node's **local** `EventStream` |
|
||||
| Node → central acks | `Publish` on `deployment-acks` | `ClusterClient.Send` to `/user/central-communication`, forwarded to the deploy-coordinator singleton |
|
||||
| Requires shared cluster membership | **yes** | no |
|
||||
|
||||
Two properties are load-bearing and easy to break:
|
||||
|
||||
- **Both comm actors are registered per node, NOT as cluster singletons.** A `ClusterClient` rotates
|
||||
across its contact points and must find a live comm actor at whichever node answers. As a
|
||||
singleton the boundary would be reachable through exactly one node, and rotation would fail
|
||||
silently against the others — acks landing or not depending on where the client happened to
|
||||
settle. `akka.cluster.client.receptionist.role` is deliberately empty for the same reason.
|
||||
- **Inbound commands go to the node-local `EventStream`, never back onto a DPS topic.** DPS is
|
||||
mesh-wide and central `SendToAll`s to *every* node, so a DPS re-publish would deliver N copies of
|
||||
every command to every subscriber.
|
||||
|
||||
Phase 2 changes no redundancy semantics: the Primary gate, ServiceLevel, and the singleton layout
|
||||
are untouched, and `redundancy-state` itself stays on DPS (it is bidirectional and built from
|
||||
`Cluster.State`, which makes it genuinely mesh-bound — the hardest remaining dependency before the
|
||||
meshes can split).
|
||||
|
||||
## Pair-local store (LocalDb — Phases 1 + 2)
|
||||
|
||||
Independently of the ServiceLevel machinery above, every **driver-role** node keeps a consolidated
|
||||
|
||||
Reference in New Issue
Block a user