OpcUaClient driver: upstream session loss never goes Bad and never recovers (live-gate find) #670
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 by the pluggable-historian live gate on docker-dev (2026-10-09,
docs/plans/2026-10-09-pluggable-historian-live-gate.md§5). This bug predates that work.Repro:
opcplc(OpcUaClient →opc.tcp://10.100.0.35:50000), tagopcplc/plc/FastUInt1, rundocker stop otopcua-opc-plcon 10.100.0.35.745) with status Good for more than 3.5 minutes.docker start otopcua-opc-plc, the node stays frozen at745Good and does not recover.The same procedure with Modbus behaves correctly: BadCommunicationError, then a BadNoCommunication outage marker about 90 s later, then recovery.
Expected:
LastSuccessfulReadfrozen, so #527 can reconnect.Check the SDK
KeepAliveandSessionReconnectHandlerwiring in the OpcUaClient driver, and whether a reconnect re-creates the subscriptions.Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
Fixed in
db6446ce, with live-gate fixes69987104(F1/F2) andbc03adb1(R2) — all merged to master.What changed in
OpcUaClientDriverDegraded(LastSuccessfulReadpreserved) + oneBadNoCommunicationper subscribed ref per outage (value retained server-side, stamped at detection time) + a quality-only alarm update. It used to stayHealthyforever.LastSuccessfulRead, so the #527 comms-loss watchdog now trips on sustained loss — its shutdown + init + resubscribe is the recovery.SessionReconnectHandleris deleted (it retried forever and, on a session recreate, cloned subscriptions the driver no longer tracked). A lost subscription (BadNoSubscription/PublishingStopped) on a live session is detected too; recovery is tied to the captured session;UpdateHealthuses a CAS loop.stale_notification_dropped.SdkTelemetry.ForLogger.Live gates (docker-dev, opc-plc fixture)
docker stopanddocker pause. F2 FAIL (R2) — the guard disarmed on the first fresh notification, before the SDK's replay arrived 4–6 s later.bc03adb1): PASS — 4 runs × 2 pause blips (20–30 s), raw subscriptions on both centrals: 1,728 notifications, 0 older or equal source timestamps (gate 2 saw ~3 regressions per node per run), first Good within ~1 s of unpause, continuous delivery through 75 s after each recovery, exactly oneBadNoCommunicationper outage per node.Follow-ups filed (TCP-stall proxy test, unused AdminUI
ReconnectPeriod, watchdog-bound recovery after an upstream restart, drop observability on the rig).