docs(historian): HistorizeToAveva opt-out semantics + config knobs + startup validation
v2-ci / build (push) Failing after 43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped

This commit is contained in:
Joseph Doherty
2026-06-11 13:24:46 -04:00
parent 7f535c0e9d
commit 6208304a44
2 changed files with 16 additions and 4 deletions
+15 -3
View File
@@ -175,13 +175,25 @@ AB CIP ALMD) route to AVEVA Historian via the Wonderware sidecar:
historian outage, older non-dead-lettered rows are evicted (oldest historian outage, older non-dead-lettered rows are evicted (oldest
first) to make room for new events. The `HistorianSinkStatus.EvictedCount` first) to make room for new events. The `HistorianSinkStatus.EvictedCount`
counter surfaces lifetime eviction events so operators can detect counter surfaces lifetime eviction events so operators can detect
silent data loss without log scraping. silent data loss without log scraping. The drain cadence, queue
capacity, and dead-letter retention are tunable via the `AlarmHistorian`
config section (`DrainIntervalSeconds`, `Capacity`,
`DeadLetterRetentionDays`); `AlarmHistorianOptions.Validate()` logs a
startup warning for an empty `SharedSecret`, a relative `DatabasePath`,
or a non-positive knob.
- `HistorianAdapterActor` - `HistorianAdapterActor`
(`src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Historian/HistorianAdapterActor.cs`) (`src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Historian/HistorianAdapterActor.cs`)
subscribes to the cluster `alerts` DPS topic, translates each subscribes to the cluster `alerts` DPS topic, translates each
`AlarmTransitionEvent``AlarmHistorianEvent`, and calls `AlarmTransitionEvent``AlarmHistorianEvent`, and calls
`EnqueueAsync` fire-and-forget. Primary-gated — only the Primary node `EnqueueAsync` fire-and-forget. The durable write is gated two ways:
historizes, giving exactly-once writes across a redundant pair. See (1) **Primary-gated** — only the Primary node historizes, giving
exactly-once writes across a redundant pair; (2) **per-alarm** — a
transition whose `HistorizeToAveva` is `false` is skipped (the flag
rides on `AlarmTransitionEvent` as a nullable bool; missing/`null`/`true`
historize, only an explicit `false` suppresses, so a cross-version
rolling restart defaults to historizing rather than dropping an audit
row). Neither gate touches the live `alerts` publish — the `/alerts`
UI always sees every transition. See
[AlarmHistorian.md §Configuration](AlarmHistorian.md#configuration) [AlarmHistorian.md §Configuration](AlarmHistorian.md#configuration)
for the `AlarmHistorian` appsettings section that enables the real sink. for the `AlarmHistorian` appsettings section that enables the real sink.
+1 -1
View File
@@ -17,7 +17,7 @@ This file covers the engine internals — predicate evaluation, state machine, p
| `Severity` | `AlarmSeverity` enum (`Low` / `Medium` / `High` / `Critical`), defined in `Core.Abstractions/IAlarmSource.cs`. Static per decision #13 — the predicate does not compute severity. The publish path bands the configured value into this four-value enum before materialising the `ScriptedAlarmDefinition`. | | `Severity` | `AlarmSeverity` enum (`Low` / `Medium` / `High` / `Critical`), defined in `Core.Abstractions/IAlarmSource.cs`. Static per decision #13 — the predicate does not compute severity. The publish path bands the configured value into this four-value enum before materialising the `ScriptedAlarmDefinition`. |
| `MessageTemplate` | String with `{TagPath}` placeholders, resolved at emission time. See below. | | `MessageTemplate` | String with `{TagPath}` placeholders, resolved at emission time. See below. |
| `PredicateScriptSource` | Roslyn C# script returning `bool`. `true` = condition active; `false` = cleared. | | `PredicateScriptSource` | Roslyn C# script returning `bool`. `true` = condition active; `false` = cleared. |
| `HistorizeToAveva` | When true, every emission is enqueued to `IAlarmHistorianSink`. Default true. Galaxy-native alarms default false since Galaxy historises them directly. | | `HistorizeToAveva` | Per-alarm opt-out of **durable** historization. When `false`, `HistorianAdapterActor` skips the `IAlarmHistorianSink` write for this alarm's transitions; the live `/alerts` fan-out is unaffected (the UI still shows every transition). Default true. Galaxy-native alarms default false since Galaxy historises them directly. |
| `Retain` | Part 9 retain flag — keep the condition visible after clear while un-acked/un-confirmed transitions remain. Default true. | | `Retain` | Part 9 retain flag — keep the condition visible after clear while un-acked/un-confirmed transitions remain. Default true. |
Illustrative definition: Illustrative definition: