Document the central alarm monitor and fan-out reversal
gateway.md describes the always-on GatewayAlarmMonitor, the session-less StreamAlarms feed, and session-less AcknowledgeAlarm. DesignDecisions.md records that the v1 "one subscriber per session / no fan-out" rule is superseded for the alarm subsystem: alarm state is gateway-wide, so the gateway monitors it centrally and fans it out to all clients. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,18 @@ fan-out may be added later with explicit backpressure semantics.
|
|||||||
Rationale: one subscriber preserves simple event ordering and failure behavior
|
Rationale: one subscriber preserves simple event ordering and failure behavior
|
||||||
while parity is being proven.
|
while parity is being proven.
|
||||||
|
|
||||||
|
### Alarms — superseded for the alarm subsystem
|
||||||
|
|
||||||
|
The single-subscriber rule above no longer applies to alarms. The gateway runs
|
||||||
|
an always-on central alarm monitor (`GatewayAlarmMonitor`) that owns one
|
||||||
|
gateway-managed worker session, caches the active-alarm set, and fans it out to
|
||||||
|
any number of clients through the session-less `StreamAlarms` RPC. Per-session
|
||||||
|
alarm auto-subscribe is removed; `AcknowledgeAlarm` is session-less and routes
|
||||||
|
through the monitor. Data-side `StreamEvents` remains one subscriber per
|
||||||
|
session. Rationale: alarm state is gateway-wide, not session-scoped — every
|
||||||
|
client wants the same current set plus updates, and forcing each to own a
|
||||||
|
worker would multiply AVEVA polling load for no benefit.
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
Decision: API key authentication for the public gateway.
|
Decision: API key authentication for the public gateway.
|
||||||
|
|||||||
+16
-5
@@ -120,13 +120,24 @@ snapshot interval without mutating session or worker state. The dashboard uses
|
|||||||
local Bootstrap CSS and JavaScript plus a small local stylesheet; it does not
|
local Bootstrap CSS and JavaScript plus a small local stylesheet; it does not
|
||||||
use a Blazor UI component library.
|
use a Blazor UI component library.
|
||||||
|
|
||||||
`/dashboard/browse` and `/dashboard/alarms` go beyond read-only snapshots: they
|
`/dashboard/browse` walks the `IGalaxyHierarchyCache` tree and reads subscribed
|
||||||
read live MXAccess data through `IDashboardLiveDataService`, which owns one
|
tag values live through `IDashboardLiveDataService`, which owns one shared,
|
||||||
shared, lazily-opened gateway session (and therefore one worker) for the whole
|
lazily-opened gateway session for the whole dashboard. `/dashboard/alarms`
|
||||||
dashboard. Browse walks the `IGalaxyHierarchyCache` tree and reads subscribed
|
reads the central alarm monitor's in-process cache directly. See
|
||||||
tag values; Alarms lists the worker's currently-active alarm set. See
|
|
||||||
`docs/GatewayDashboardDesign.md`.
|
`docs/GatewayDashboardDesign.md`.
|
||||||
|
|
||||||
|
The gateway runs an always-on central alarm monitor (`GatewayAlarmMonitor`):
|
||||||
|
one gateway-owned worker session subscribes the configured AVEVA alarm
|
||||||
|
provider, caches the active-alarm set (reconciled periodically against the
|
||||||
|
worker's snapshot), and fans it out to every client through the session-less
|
||||||
|
`StreamAlarms` RPC — the stream opens with the current active-alarm snapshot,
|
||||||
|
then streams live transitions. `AcknowledgeAlarm` is session-less and routes
|
||||||
|
through the monitor. Clients never open a worker session to see alarms, and
|
||||||
|
alarm monitoring is independent of client lifecycle; the monitor re-opens its
|
||||||
|
session if the worker faults. Gated by `MxGateway:Alarms:Enabled` — see
|
||||||
|
`docs/DesignDecisions.md` for why this reverses the v1 single-subscriber rule
|
||||||
|
for the alarm subsystem.
|
||||||
|
|
||||||
Dashboard routes use the same API-key verifier as gRPC. `/dashboard/login`
|
Dashboard routes use the same API-key verifier as gRPC. `/dashboard/login`
|
||||||
accepts the API key in a form body, validates the configured `admin` scope,
|
accepts the API key in a form body, validates the configured `admin` scope,
|
||||||
and issues an HTTP-only secure cookie for subsequent dashboard requests.
|
and issues an HTTP-only secure cookie for subsequent dashboard requests.
|
||||||
|
|||||||
Reference in New Issue
Block a user