OpcUaClient native-alarm feed not restored by reconcile / lost on a non-respawning deploy #662
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found during the #657 live gate on the docker-dev rig (2026-10-09). This is not fixed by #657.
Symptom
An OpcUaClient driver's native-alarm feed silently stops. Nothing marks it as stopped: the condition freezes at its last state while upstream keeps emitting events. Only a driver respawn brings it back (e.g. toggling the DriverConfig so the next deploy recreates the driver).
Case 1: a deploy that doesn't respawn the driver
opcua-sub-2) and logged no alarm re-subscribe. Central's condition then stayed frozen at its 10:42:11 state for 25+ minutes while opc-plc kept emitting.Case 2: after an outage
opcua-sub-20). The alarm subscription was never retried.Evidence
central-1 container logs, 10:12–10:42 and 10:39:04–10:40:18 (2026-10-09).
Likely area
The resubscribe/reconcile path that
DriverInstanceActorruns after init or reconnect (#630: "the actor re-subscribes after every successful init") coversISubscribablebut apparently notIAlarmSource.SubscribeAlarmsAsync. The OpcUaClient alarm subscription also has a "gated until reconnect" state that nothing re-drives.Expected
Every path that restores the data subscription also restores the alarm subscription: a non-respawning deploy, a reconnect, and the periodic reconcile. A failed alarm subscribe is retried, or surfaces in driver health/diagnostics instead of silently gating the feed.
Test
An end-to-end test through
DriverHostActor/DriverInstanceActor:Related: #657, #641, #630.
Fixed on master
83d129d1(5067509d+ review follow-up28ca04e4).Root cause
In
DriverInstanceActor, the data re-subscribe path (HandleSubscribeAsync, thenUnsubscribeAsync, thenDetachSubscription) also ranDetachAlarmSource. That unhookedOnAlarmEventand forgot the alarm handle.Every deploy's bulk
SetDesiredSubscriptionspush re-subscribes the data of each driver it keeps. So after any deploy that did not respawn a driver, the alarm subscription still logged "established" but its events reached nobody. This explains both 10:12 and 10:42. The bug is in generic actor code, so it hit every native-alarm driver (OpcUaClient, Galaxy, FOCAS, MTConnect, AbCip), not just OpcUaClient.The #488 health-poll reconcile only checked data. That is why a failed alarm subscribe after the outage was never retried (case 2).
Fix
DetachDataSubscription. OnlyDisconnectObserved,ForceReconnectandPostStopdetach both data and alarms.ReconcileAlarmSubscriptionruns on each health-poll tick.SubscribeAlarmsAsyncdetaches its handler and removes the half-built subscription from the session, with a 5 s bound. Events from an unregistered subscription id are dropped.Tests
DriverHostActorandDriverInstanceActor(NativeAlarmFeedSurvivesDeployTests): a deploy that only adds another driver re-subscribes DI-1's data without re-initialising it, and an upstream Raise still reaches the condition.Not re-gated live on the docker-dev rig. The end-to-end test reproduces the exact actor path the rig logs showed.