fix(runtime): keep native-alarm feed across data re-subscribes; reconcile retries alarms (#662)
A data re-subscribe (every deploy's bulk SetDesiredSubscriptions push to a kept driver) dropped the prior data subscription through the full DetachSubscription, which also unhooked OnAlarmEvent and forgot the alarm handle. On any deploy that did not respawn the driver, the alarm subscription kept logging "established" while every event reached nobody until a reconnect or respawn. The data path now uses DetachDataSubscription; only a lost connection and PostStop detach both. The #488 health-poll reconcile only looked at data, so an alarm subscribe that failed on (re)connect gated the feed for the life of the connection. ReconcileAlarmSubscription now re-attaches a missing handler and re-subscribes a stale/missing alarm handle every tick. OpcUaClient removes a half-built alarm subscription from its session when SubscribeAlarmsAsync throws, so the new retries cannot accumulate. Tests: actor-level data-resubscribe + reconcile-retry tests and an end-to-end NativeAlarmFeedSurvivesDeployTests through DriverHostActor; all three fail against the unfixed actor. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -242,6 +242,19 @@ Things to know before touching any of this:
|
||||
re-subscribing** so a filtering driver does not accumulate two overlapping ones. There is still
|
||||
deliberately no unsubscribe-on-**empty**: a removed alarm tag's condition node is torn down on the
|
||||
address-space rebuild and `ForwardNativeAlarm` drops any transition whose `ConditionId` no longer maps.
|
||||
- ⚠️ **A data re-subscribe must not touch the alarm feed (#662).** Every deploy's bulk push re-sends
|
||||
`SetDesiredSubscriptions` to every kept driver, and `HandleSubscribeAsync` drops the prior DATA
|
||||
subscription first. That teardown used to be the full `DetachSubscription`, which also unhooked
|
||||
`OnAlarmEvent` and forgot the alarm handle — so on any deploy that did **not** respawn a driver (e.g. one
|
||||
that only disabled another driver) its alarm subscription kept logging "established" while every event
|
||||
reached nobody, until a reconnect or respawn. The data path now uses `DetachDataSubscription`; only a lost
|
||||
connection (`DisconnectObserved` / `ForceReconnect`) and `PostStop` detach both. The **#488 periodic
|
||||
reconcile covers alarms too** (`ReconcileAlarmSubscription`): it re-attaches a missing `OnAlarmEvent`
|
||||
handler and re-subscribes when the live alarm handle does not match the desired set, so an alarm subscribe
|
||||
that failed on (re)connect — a session not yet ready after an outage — is retried every health-poll tick
|
||||
instead of gating the feed for the life of the connection. OpcUaClient removes a half-built alarm
|
||||
subscription from its session when the subscribe throws, so those retries do not accumulate.
|
||||
End-to-end pin: `NativeAlarmFeedSurvivesDeployTests`.
|
||||
- **Restart tests must assert a FUNCTION, never existence.** `RestartDriver_respawns_the_child_without_an_actor_name_collision`
|
||||
asserts only that a child exists after a restart, and it passed green against the dead driver 03/S16
|
||||
describes. It is kept — its own subject, the `InvalidActorNameException`, is real — but the load-bearing
|
||||
|
||||
Reference in New Issue
Block a user