OPC UA condition events: ConditionRefresh can be overtaken by older deferred events #854

Closed
opened 2026-11-11 05:24:28 -05:00 by dohertj2 · 1 comment
Owner

From the #838 deadlock fix review. When a folder subscription's SDK event queue is full, condition events are deferred per condition (newest kept, oldest dropped past 1024/condition or 65,536 total; meters otopcua.opcua.condition_events.deferred / discarded). A client that runs ConditionRefresh during that overload may still receive older deferred events after RefreshEnd. They stay in per-condition order and the newest arrives last, so the client converges, but a strict client could briefly show stale state. Making refresh wait for the queues would block a service call on the stalled drain. Revisit if a consumer (e.g. ScadaBridge) is affected.

From the #838 deadlock fix review. When a folder subscription's SDK event queue is full, condition events are deferred per condition (newest kept, oldest dropped past 1024/condition or 65,536 total; meters `otopcua.opcua.condition_events.deferred` / `discarded`). A client that runs ConditionRefresh during that overload may still receive older deferred events after RefreshEnd. They stay in per-condition order and the newest arrives last, so the client converges, but a strict client could briefly show stale state. Making refresh wait for the queues would block a service call on the stalled drain. Revisit if a consumer (e.g. ScadaBridge) is affected.
dohertj2 added the type:followuppriority:p3 labels 2026-11-11 05:24:28 -05:00
Author
Owner

Fixed for Server-object (i=2253) subscriptions — the path ScadaBridge uses (1622d07f, fe48458a, a0e9a455). Pushed to master in 03e51457. With nothing deferred, ConditionRefresh/ConditionRefresh2 is the plain walk off Lock (0–3 ms Lock hold at 3000 conditions, was ~100 ms in the first cut). While deferring, one short Lock hold takes a sequence cut + frozen snapshots of retained conditions, the replay is queued off Lock, and older deferred events are withheld from that subscription only (re-sent conditions, or Retain=true ones omitted because not retained — never ACL-omitted ones). Meter otopcua.opcua.condition_events.superseded. Two independent concurrency reviews; no deadlock, no lost events for non-refreshing subscribers. Folder subscriptions keep the residual: #855.

Fixed for Server-object (`i=2253`) subscriptions — the path ScadaBridge uses (`1622d07f`, `fe48458a`, `a0e9a455`). Pushed to master in `03e51457`. With nothing deferred, ConditionRefresh/ConditionRefresh2 is the plain walk off `Lock` (0–3 ms Lock hold at 3000 conditions, was ~100 ms in the first cut). While deferring, one short `Lock` hold takes a sequence cut + frozen snapshots of retained conditions, the replay is queued off `Lock`, and older deferred events are withheld from that subscription only (re-sent conditions, or Retain=true ones omitted because not retained — never ACL-omitted ones). Meter `otopcua.opcua.condition_events.superseded`. Two independent concurrency reviews; no deadlock, no lost events for non-refreshing subscribers. Folder subscriptions keep the residual: #855.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#854