fix(dcl): treat OPC UA BadResourceUnavailable as transient Bad; Bad+null keeps last-known value (ScadaBridge#112)
OtOpcUa's out-of-process script runner publishes 0x80040000 with a null value. - OpcUaDataConnection: logs entry/recovery once per tag, names the symbolic status in read errors; never a disconnect (not in the reconnect status set). - InstanceActor: a Bad update with no value is a quality-only transition (keep value, quality Bad, stream publish, no script/alarm/waiter re-eval), matching the connection-drop rule. Bad with a value is unchanged. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -399,6 +399,7 @@ Subscription demand survives connection transitions through coalescing and owner
|
||||
The DCL manages connection lifecycle automatically:
|
||||
|
||||
1. **Connection drop detection**: When a connection to a data source is lost, the DCL immediately pushes a value update with quality `bad` for **every tag subscribed on that connection**. Instance Actors see the staleness immediately and publish it to the site stream / debug view; **script and alarm actors are deliberately NOT re-notified on a quality-only change** (no value changed — re-evaluating triggers would cause spurious firings). Scripts observe quality on their next attribute read; a computed alarm holds its last-known state until fresh values arrive.
|
||||
**Per-tag Bad with no value is handled the same way (ScadaBridge#112).** A tag update whose quality is `bad` and whose value is null — OPC UA servers commonly omit the value on a Bad status, and OtOpcUa always does — is a quality-only transition at the Instance Actor: the last-known value is kept, quality goes `Bad`, the stream/debug view is told, scripts/alarms/`WaitForAttribute` waiters are not re-evaluated, and the next Good update recovers it. A Bad update that carries a value still stores that value. This covers OtOpcUa's `BadResourceUnavailable` (`0x80040000`, its out-of-process script runner's "worker restarted / runner unavailable" on virtual and Calculation tags, lmxopcua#780): the OPC UA adapter treats it as a plain per-node Bad — never a connection fault (it is not in the DataConnectionActor's session/secure-channel reconnect set), no subscription teardown — logs one Information line per tag on entry and one on recovery, and names it in read errors (`0x80040000 BadResourceUnavailable (source node temporarily unable to compute the value)`; every other Bad read error now carries its symbolic name too).
|
||||
2. **Auto-reconnect with fixed interval**: The DCL retries the connection at a configurable fixed interval (e.g., every 5 seconds). The retry interval is a **shared setting for all data connections** (`ReconnectInterval` in the Shared Settings table). This is consistent with the fixed-interval retry philosophy used throughout the system. Individual gRPC/OPC UA operations (reads, writes) fail immediately to the caller on error; there is no operation-level retry within the adapter.
|
||||
3. **Connection state transitions**: The DCL tracks each connection's state as `connected`, `disconnected`, or `reconnecting`. All transitions are logged to Site Event Logging (event type `connection`): the initial connect (`Connection established on … endpoint`, Info — added by review 2026-10-21, it previously logged nothing), connection lost / reconfigured (`Warning` / `Info`), restored on reconnect (`Info`) and failover (`Warning`).
|
||||
4. **Transparent re-subscribe**: On successful reconnection, the DCL automatically re-establishes all previously active subscriptions for that connection. Instance Actors require no action — they simply see quality return to `good` as fresh values arrive from restored subscriptions.
|
||||
|
||||
Reference in New Issue
Block a user