fix(opcua): condition events never block under the node-manager lock; folder-event Part 3 note (#838)
#838(a): each notifier's SDK MonitoredNode2 drains a bounded channel (4096, FullMode=Wait) and the synchronous NodeState.ReportEvent blocks when it is full. Condition events are reported under Lock, and the delivery task takes Lock on a verdict-cache miss (the SDK's own GetNodeMetadata, flag off too, and #826's IsNotifierEventVisibleTo). A burst of >4096 events under one Lock hold therefore deadlocked the node manager -- FolderEventFloodWireTests stalled at exactly 4097 events with enforcement on AND off (so it predates #826). ReportConditionEvent now goes through ReportEventWithoutBlocking: ReportEventAsync completes inline while channels have room (unchanged normal path); on overflow the report continues asynchronously holding no thread or lock, and later reports queue behind it so events keep report order. The deferred work holds only frozen snapshots and drains once Lock is released; client delivery stays bounded by each item's queue. #838(b): documented in docs/security.md that Part 3 ReceiveEvents applies to the event's EventType and SourceNode (the SDK check, kept first), not to the notifier; our decision is layered on top and non-condition events on a folder item fail closed under enforcement. The reflection item stays open.
This commit is contained in:
@@ -204,6 +204,13 @@ Two things to know before relying on any of this:
|
||||
enforcement (`ServerEventRig.TagReferences()`); null ⇒ none (fail closed). Tests:
|
||||
`UnsFolderScopeWireTests.A_moved_alarm_stops_reaching_its_old_folders_subscribers…`,
|
||||
`NativeAlarmFolderEventAclWireTests`.
|
||||
⚠️ **Never report an event with the synchronous `NodeState.ReportEvent` while holding `Lock` (#838).** Each
|
||||
notifier's `MonitoredNode2` drains a BOUNDED channel (4096, `FullMode = Wait`) and its delivery task takes `Lock` on a
|
||||
verdict-cache miss (SDK `GetNodeMetadata` — flag off too — and #826's check); sync `ReportEvent` blocks on a full
|
||||
channel ⇒ a >4096 burst under one `Lock` hold deadlocked the node manager (stalled at 4097). Condition events go
|
||||
through `ReportEventWithoutBlocking` (async on overflow, ordered chain). Folder events follow Part 3's shape —
|
||||
`ReceiveEvents` on EventType + SourceNode (SDK check, kept first) AND our decision; non-condition events on a
|
||||
folder item fail closed under enforcement. Tests: `FolderEventFloodWireTests`.
|
||||
- **ns=0 standard nodes stay ungated by design, even with `Security:Acl:Enabled`** (#617) — `ServerStatus`,
|
||||
`NamespaceArray`, `ServiceLevel` etc. are served by the SDK's core node manager outside our authorizer and
|
||||
clients read them to connect and to judge redundancy health; they carry no plant data. Every raw/UNS node,
|
||||
|
||||
Reference in New Issue
Block a user