docs(alarms): #656 re-statement flag + ActiveAcknowledged kind (AlarmTracking, OpcUaClient, Galaxy, ScriptedAlarms, CLAUDE.md)
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -94,6 +94,8 @@ Full per-field descriptions live in `Config/GalaxyDriverOptions.cs`. The full JS
|
||||
|
||||
The session-less alarm feed (`GatewayGalaxyAlarmFeed`) and alarm acknowledger (`GatewayGalaxyAlarmAcknowledger`) run on a separate always-on `_ownedMxClient` that is intentionally **not** recreated when `ReconnectSupervisor` rebuilds the worker session. The feed has its own re-invoke loop (~5 s backoff) that reopens `StreamAlarms` after any stream fault, and gRPC.NET's channel auto-reconnect recovers the underlying HTTP/2 connection after a gateway restart — so both the alarm stream and individual ack calls recover without client replacement. The acknowledger is completely stateless between calls: each `AcknowledgeAsync` issues a single unary RPC and returns; no dead-client state is latched on failure. Channel-level keepalive hardening (TCP keep-alive intervals, gRPC ping frames) would require exposing additional knobs on `MxGatewayClientOptions` in the sibling `mxaccessgw` repo — a future option if flaky long-lived connections are observed in production.
|
||||
|
||||
Every (re)open of `StreamAlarms` replays the gateway's active-alarm snapshot. `GatewayGalaxyAlarmFeed` maps each entry to a transition flagged `IsRestatement` (#656): `Active` → `Retrigger` (upstream's unack is authoritative), `ActiveAcked` → `ActiveAcknowledged` (one atomic active+acked projection — the old `Acknowledge` mapping projected an acked alarm **inactive** on a cold host), `Inactive` → `Clear`. The host writes no `/alerts` row for a replayed entry that changes nothing the condition shows, so a gateway reconnect no longer duplicates history; live `Transition` messages are never flagged. The gateway folds UnackRtn and AckRtn into `Inactive`, so an inactive-unacked alarm cannot be distinguished at reconnect (gateway contract limit).
|
||||
|
||||
## Testing
|
||||
|
||||
- **Unit tests**: `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests/` — fakes the gateway gRPC surface; covers Browse, Runtime, Health, and Config in isolation.
|
||||
|
||||
@@ -101,7 +101,10 @@ initialise (the AdminUI form drops them on the next save). Pinned by
|
||||
> EventId** (Part 9 §5.7.3). The event's `ActiveState/Id` + `AckedState/Id` are selected and turned into the
|
||||
> `Raise`/`Acknowledge`/`Clear`/`Retrigger` kinds the host projector consumes (without a kind no upstream alarm could ever
|
||||
> show active); the kinds are emitted from the state **last told to the host** per RawPath, so an identical re-delivery
|
||||
> emits nothing (no re-raise, which would un-ack). Condition **branch** events (non-null `BranchId`) are ignored.
|
||||
> emits nothing (no re-raise, which would un-ack). An inactive → active+acked move is ONE `ActiveAcknowledged` (#656; it
|
||||
> used to be `Raise` + `Acknowledge`, a client-visible unacked intermediate). The first event per condition after a
|
||||
> start or deploy respawn is flagged `IsRestatement`, so the host writes no duplicate "Activated" row when its
|
||||
> condition already shows that state (see `docs/AlarmTracking.md`). Condition **branch** events (non-null `BranchId`) are ignored.
|
||||
> **`ConditionRefresh`** is called after the event item is created, after every in-place reconnect, and on a
|
||||
> `RefreshRequired` event, so a condition already active upstream is reported at subscribe; `RefreshStart`/`RefreshEnd`
|
||||
> markers are dropped. A server without it (`BadNotSupported`/`BadMethodInvalid`/…) is logged once and tolerated.
|
||||
|
||||
Reference in New Issue
Block a user