Skip to content
Closed
Show file tree
Hide file tree
Changes from 111 commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
d1c7ca9
Add live NodeManager lifecycle support
marcschier Jul 14, 2026
b0d3e5e
Harden live NodeManager lifecycle coordination
marcschier Jul 17, 2026
bb3d5c0
Address PR feedback for hosted lifecycle tests
marcschier Jul 18, 2026
85c8120
Fix lifecycle CI coverage and startup request race
marcschier Jul 19, 2026
2afe352
Adapt lifecycle tests to session-scoped cancellation
marcschier Jul 19, 2026
1c048e9
Merge branch 'master' into copilot/3993-live-node-manager-lifecycle
marcschier Jul 21, 2026
ffee55a
Handle monitored items when nodes are removed
marcschier Jul 22, 2026
09ab190
Address subscription logging review feedback
marcschier Jul 22, 2026
fa9e786
Stabilize chained triggering CI test
marcschier Jul 22, 2026
f9f03ef
Merge remote-tracking branch 'origin/master' into copilot/3993-live-n…
marcschier Jul 22, 2026
757908c
Merge remote-tracking branch 'origin/master' into copilot/3993-live-n…
marcschier Jul 23, 2026
bcf1586
Merge origin/master into copilot/3993-live-node-manager-lifecycle
marcschier Jul 23, 2026
b177a09
Merge origin/master into copilot/3993-live-node-manager-lifecycle
marcschier Jul 25, 2026
230c10e
Add shadow NodeManager reload support
marcschier Jul 21, 2026
1e8f81f
Add lossless WoT conversion and source generation
marcschier Jul 21, 2026
1b261e6
Add injectable WoT protocol bindings
marcschier Jul 21, 2026
4ddf948
Add registry-first WoT Connectivity runtime
marcschier Jul 21, 2026
c4a773f
Fix WoT converter: mandatory digest, shared resolution context, resol…
marcschier Jul 21, 2026
56c8a18
Route ownership-sensitive monitored-item ops to owning NodeManager
marcschier Jul 21, 2026
1a95bac
Harden WoT protocol executors (MQTT TLS, Modbus validation, HTTP redi…
marcschier Jul 21, 2026
034bc30
Make WoT registry commits atomically durable and populate typed events
marcschier Jul 21, 2026
49c37fa
Sync corrected WoT Connectivity V2 model
marcschier Jul 21, 2026
7026bdb
Reject oversized Modbus quantities
marcschier Jul 21, 2026
2393913
Fix HTTP test server analyzer warning
marcschier Jul 21, 2026
feb8861
Use explicit HTTP header search comparison
marcschier Jul 22, 2026
0c4a159
Align WoT Connectivity proof to combined 1.1 spec model
marcschier Jul 22, 2026
2d85363
Fix WoT proof test analyzer warnings
marcschier Jul 22, 2026
f6633e7
Align WoT converter with portable Binding identity
marcschier Jul 23, 2026
b23ebc9
Make WoT NodeSet conversion native-first
marcschier Jul 23, 2026
448acd6
Address WoT model concept review feedback
marcschier Jul 24, 2026
89cc2c6
Address WoT mapping review feedback
marcschier Jul 24, 2026
5e7abf7
Prefer context prefixes for WoT QualifiedNames
marcschier Jul 24, 2026
4c94ca2
Implement selectable WoT projection retirement
marcschier Jul 25, 2026
9188c55
Fix ordinary Bad_NodeIdUnknown samples blocking monitored item queues
marcschier Jul 25, 2026
e7bdfbf
Address PR review feedback on NodeManager lifecycle
marcschier Jul 25, 2026
91437c4
Merge protected missing-node publish into the regular publish path
marcschier Jul 25, 2026
37397e5
Consolidate WoT bindings and add WoT-driven aggregation sample
marcschier Jul 25, 2026
9bd62c9
Apply code style and analyzer fixes to WoT bindings branch
marcschier Jul 25, 2026
ba07fbd
Wire the DI NodeManager fluent builder DataType resolver
marcschier Jul 25, 2026
2e298af
Address PR review feedback on WoT docs and sample layout
marcschier Jul 26, 2026
04e7c87
Merge branch 'master' into copilot/3993-live-node-manager-lifecycle
marcschier Jul 26, 2026
2425fc0
Raise PR patch coverage from 70% to 91% with unit and integration tests
marcschier Jul 26, 2026
8e49672
Consolidate NodeManager lifecycle interfaces per review feedback
marcschier Jul 26, 2026
539478a
Merge remote-tracking branch 'origin/copilot/3993-live-node-manager-l…
marcschier Jul 26, 2026
c3f167c
Fold ISubscriptionDeletionRegistry into ISubscriptionManager
marcschier Jul 26, 2026
6b72454
Harden queue drain, monitored item cleanup, and continuation point te…
marcschier Jul 26, 2026
ce9aedb
Fix net48 test failures and remove dead WoT mapping code
marcschier Jul 26, 2026
269a0a1
Merge copilot/3993-live-node-manager-lifecycle into marcschier/wot-bi…
marcschier Jul 27, 2026
cc64796
Let OperationContext own the request scope and invalidate history con…
marcschier Jul 27, 2026
b376dc6
Fold detached ownership into MonitoredItem and decouple monitored ite…
marcschier Jul 27, 2026
7304ff0
Fix request scope guard and relocate subscription lifecycle markers
marcschier Jul 27, 2026
7e9dd63
Simplify the missing-Node marker to a single pending value
marcschier Jul 27, 2026
3b6311d
Dispose the PubSub operation context
marcschier Jul 27, 2026
53793b3
Document the request scope and subscription marker changes
marcschier Jul 27, 2026
773e6a1
Simplify the queue handler and make session closing one way
marcschier Jul 27, 2026
8bbec6c
Clarify optional WoT binder registration
marcschier Jul 25, 2026
a9d04e3
Ignore WoT inputs before source generation
marcschier Jul 26, 2026
5018f9a
Fix generated method argument symbols
marcschier Jul 26, 2026
de9603b
Harden HTTP headers across redirects
marcschier Jul 26, 2026
0a86257
Fix Modbus multi-bit coil operations
marcschier Jul 26, 2026
156bf9a
Harden WoT registry manifest persistence
marcschier Jul 26, 2026
9e8607d
Restrict aggregation server to executable TFMs
marcschier Jul 26, 2026
f0cd330
Fix WoT binding legacy TFM builds
marcschier Jul 25, 2026
6785b78
Align binding tests with hardened activation
marcschier Jul 27, 2026
3d05a2e
Restore the pre-PR shape of the queue and subscription manager
marcschier Jul 27, 2026
4374d75
Align registry tests with fail-closed persistence
marcschier Jul 27, 2026
c339a9a
Merge branch 'master' into copilot/3993-live-node-manager-lifecycle
marcschier Jul 27, 2026
c0fbe67
Persist the deleted and detached state explicitly
marcschier Jul 27, 2026
7db3274
Restore triggering semantics and allow transfer from a closing session
marcschier Jul 27, 2026
99c6127
Let OperationContext own the request scope and invalidate history con…
marcschier Jul 27, 2026
7878d90
Fold detached ownership into MonitoredItem and decouple monitored ite…
marcschier Jul 27, 2026
943a16f
Fix request scope guard and relocate subscription lifecycle markers
marcschier Jul 27, 2026
fc55879
Simplify the missing-Node marker to a single pending value
marcschier Jul 27, 2026
d6d4822
Dispose the PubSub operation context
marcschier Jul 27, 2026
b6b2c62
Document the request scope and subscription marker changes
marcschier Jul 27, 2026
212e7a4
Simplify the queue handler and make session closing one way
marcschier Jul 27, 2026
54d5433
Drain retired event generations on delete
marcschier Jul 26, 2026
f5d7bb4
Harden shadow-retired lifecycle draining
marcschier Jul 26, 2026
a5687ce
Reject mismatched Modbus register widths
marcschier Jul 27, 2026
1631265
Rollback pristine registry staging failures
marcschier Jul 27, 2026
b172052
Merge current lifecycle head and restore retired notifications
marcschier Jul 27, 2026
58caa73
Fix redundant monitored item lifecycle persistence
marcschier Jul 27, 2026
20efe2d
Merge commit '58caa73227fa6082064d93176593fd1d5701001c' into integrat…
marcschier Jul 28, 2026
d2d35f8
Fix subscription transfer race with session close
marcschier Jul 28, 2026
8364c5d
Prevent stale subscription timer expiration
marcschier Jul 28, 2026
e44d339
Merge commit '8364c5d4732095592938b540eec4de275ca96dd0' into integrat…
marcschier Jul 28, 2026
f521617
Tolerate requests that arrive before startup publishes the request ma…
marcschier Jul 28, 2026
c4918dc
Merge commit 'f521617b6' into integrate/wot-proof-20260727
marcschier Jul 28, 2026
d770799
Merge branch 'master' into copilot/3993-live-node-manager-lifecycle
marcschier Jul 28, 2026
92beb3e
Tolerate requests that arrive before startup publishes the request ma…
marcschier Jul 28, 2026
761cbb9
Merge remote-tracking branch 'origin/copilot/3993-live-node-manager-l…
marcschier Jul 28, 2026
21f39bd
Merge commit '92beb3e90' into integrate/wot-proof-20260727
marcschier Jul 28, 2026
098f0fc
Move session-close ownership onto ISubscription
marcschier Jul 28, 2026
28bb956
Keep declaration-backed method arguments when skipping method types
marcschier Jul 28, 2026
33fd3ba
Disambiguate the server-side ISession and ISubscription migration notes
marcschier Jul 28, 2026
cd9bb34
Merge master and consume the shared xRegistry packages
marcschier Jul 28, 2026
71df17b
Merge remote-tracking branch 'origin/copilot/3993-live-node-manager-l…
marcschier Jul 28, 2026
6759683
Merge the remote integration branch
marcschier Jul 28, 2026
a9bf88e
Merge branch 'master' into copilot/3993-live-node-manager-lifecycle
marcschier Jul 28, 2026
fe1a60e
Merge the latest base branch (ISA-95, transfer security, identifier f…
marcschier Jul 28, 2026
ba12503
Merge master into WoT proof branch
marcschier Jul 28, 2026
dfabaeb
Derive WotRegistryClient from the shared XRegistryClient
marcschier Jul 28, 2026
038bc06
Make subscription transfer effects transactional
marcschier Jul 28, 2026
aa9b525
Add a WoT blob store implementing the xRegistry resource store contract
marcschier Jul 29, 2026
6f15e57
Merge remote-tracking branch 'upstream/master' into sync/proof-merge-…
marcschier Jul 29, 2026
c588bf9
Let a WoT registry keep its document bytes in an injected resource store
marcschier Jul 29, 2026
8226ae4
Document the WoT resource store and fix its net48 build
marcschier Jul 29, 2026
9ba510e
Merge remote-tracking branch 'origin/marcschier/wot-binding-xregistry…
marcschier Jul 29, 2026
e110238
Add WoT materialization and polling extension points (#4108, #4109, #…
marcschier Jul 29, 2026
3ea7170
Address code review findings and PR feedback
marcschier Jul 29, 2026
46e5e5f
Harden server-internal shutdown coordination
marcschier Jul 30, 2026
957c245
Address review feedback on async disposal, docs and locking
marcschier Jul 30, 2026
a68f548
Stop the server tests depending on the WoT registry
marcschier Jul 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions UA.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
<Project Path="samples/MinimalCalcServer/MinimalCalcServer.csproj" />
<Project Path="samples/MinimalClient/MinimalClient.csproj" />
<Project Path="samples/PumpDeviceIntegrationServer/PumpDeviceIntegrationServer.csproj" />
<Project Path="samples/WotCon/AggregationClient/AggregationClient.csproj" />
<Project Path="samples/WotCon/AggregationServer/AggregationServer.csproj" />
<Project Path="samples/WotCon/FlatTagServer/FlatTagServer.csproj" />
<Project Path="samples/Quickstarts.Servers/Quickstarts.Servers.csproj" />
<Project Path="samples/RedundantClient/RedundantClient.csproj" />
</Folder>
Expand Down Expand Up @@ -93,6 +96,8 @@
<Project Path="src/Opc.Ua.Redundancy.Client/Opc.Ua.Redundancy.Client.csproj" />
<Project Path="src/Opc.Ua.Redundancy.Kubernetes/Opc.Ua.Redundancy.Kubernetes.csproj" />
<Project Path="src/Opc.Ua.WotCon/Opc.Ua.WotCon.csproj" />
<Project Path="src/Opc.Ua.WotCon.Bindings/Opc.Ua.WotCon.Bindings.csproj" />
<Project Path="src/Opc.Ua.WotCon.Bindings.Mqtt/Opc.Ua.WotCon.Bindings.Mqtt.csproj" />
<Project Path="src/Opc.Ua.WotCon.Client/Opc.Ua.WotCon.Client.csproj" />
<Project Path="src/Opc.Ua.WotCon.Server/Opc.Ua.WotCon.Server.csproj" />
<Project Path="src/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj" />
Expand Down Expand Up @@ -262,6 +267,8 @@
<Project Path="tests/Opc.Ua.Tools.Tests/Opc.Ua.Tools.Tests.csproj" />
<Project Path="tests/Opc.Ua.Types.Tests/Opc.Ua.Types.Tests.csproj" />
<Project Path="tests/Opc.Ua.WotCon.Tests/Opc.Ua.WotCon.Tests.csproj" />
<Project Path="tests/Opc.Ua.WotCon.Bindings.Tests/Opc.Ua.WotCon.Bindings.Tests.csproj" />
<Project Path="tests/Opc.Ua.WotCon.Samples.Tests/Opc.Ua.WotCon.Samples.Tests.csproj" />
</Folder>
<Folder Name="/tests/TestFramework/">
<Project Path="tests/Opc.Ua.Test.Common/Opc.Ua.Test.Common.csproj" />
Expand Down
3 changes: 3 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ Here is a list of available documentation for different topics:
* [Kubernetes High Availability Deployment](Kubernetes.md) - Consolidated Kubernetes guide for the `Opc.Ua.Redundancy.Kubernetes` package: Lease leader election, EndpointSlice peer discovery, ServiceLevel-driven readiness, StatefulSet/Deployment and Service manifests, RBAC, probes, time sync, secrets, and GDS/NTRS registration.
* [Redundant Sample Integration Tests](RedundancySampleTests.md) - Process-level integration tests that launch the `RedundantServer` / `RedundantClient` / `RedundantPubSub` sample apps and assert on their failover, reconnect, and data-loss-visibility behavior; short-haul variants run on every PR, long-haul soak variants run via dedicated manual/scheduled GitHub Actions and Azure DevOps jobs (`SAMPLE_HA_DURATION_MINUTES`).
* [Dependency Injection](DependencyInjection.md) - The unified `services.AddOpcUa()` / `IOpcUaBuilder` surface for hosting OPC UA components in `Microsoft.Extensions.DependencyInjection` / the .NET Generic Host (servers as `IHostedService`, options via `Action<T>` or `IConfiguration`, AOT-friendly).
* [WoT Connectivity](WoTConnectivity.md) - OPC 10100-1 asset connectivity, the WoT Connectivity 1.1 registry/client, dependency-closure materialization, and runtime NodeSet projection.
* [WoT protocol bindings](WotBindings.md) - The bindings that ship today (planner/executor architecture, bundled and separate packages, operation coverage, target mapping, lazy channels, generation lifetime) and the contributor guide for adding your own, with a complete memory binding, registration, diagnostics, tests, packaging, TFM, trimming, and NativeAOT guidance.
* [WoT aggregation sample](../samples/WotCon/README.md) - Two flat OPC UA sources aggregated into a runtime-loaded DI/Machinery/Pumps Pump model, including commands, Refresh, monitoring, replacement, troubleshooting, and NativeAOT publishing.
* [AuthorizationService](AuthorizationService.md) - Modern Part 12 `StartRequestToken` / `FinishRequestToken`, `ITokenIssuer`, and GDS token issuance.
* [Fuzz testing](../fuzzing/Fuzzing.md) - SharpFuzz + afl-fuzz + libFuzzer integration. Three areas: `Encoders` (Binary/JSON/XML decoders, built-in type readers, parser entry points), `Certificates` (`X509CRL`, X509 extension parsers, `PEMReader`, `Pkcs10CertificationRequest`, ASN.1 helpers), and `Network` (UA-SC framing via `Opc.Ua.Core.Diagnostics` + internal `TcpMessageParsers` seam on `Opc.Ua.Core`). The [`fuzz-tester`](../.github/agents/fuzz-tester.agent.md) custom agent drives the whole toolchain autonomously: it detects OS-available engines, runs them in parallel, fixes novel findings per repo guidelines, adds the failing input as a regression asset, and pushes one commit per fix until the user says stop.
* [KeyCredentialService](KeyCredentialService.md) - Pull, Push, and experimental bridge guidance for Part 12 KeyCredential flows.
Expand Down
32 changes: 31 additions & 1 deletion docs/RuntimeNodeSets.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Use the [source-generated path](SourceGeneratedNodeManagers.md) when you want co

`AddRuntimeNodeSet` on `IOpcUaServerBuilder` remains the startup path: its factory is created before the server starts and its NodeSet is imported during `CreateAddressSpaceAsync`.

Running servers also expose `INodeManagerLifecycle`. Resolve it from dependency injection in a hosted server, or use `StandardServer.NodeManagerLifecycle` when constructing the server directly. The lifecycle provider can add, reload, and remove runtime NodeSets without restarting the server.
Running servers also expose `INodeManagerLifecycle`. Resolve it from dependency injection in a hosted server, or use `StandardServer.NodeManagerLifecycle` when constructing the server directly. The lifecycle provider can add, reload, shadow-reload, and remove runtime NodeSets without restarting the server.

```csharp
public sealed class ModelLoader(INodeManagerLifecycle lifecycle)
Expand Down Expand Up @@ -55,6 +55,36 @@ Each add returns an immutable `NodeManagerRegistration`, and reload returns the

The rules that apply to every NodeManager registered at runtime -- what happens to MonitoredItems, Browse continuation points, namespace indexes, DataTypes, and change notifications, and which NodeManagers may be reloaded at all -- are described once in [Registering NodeManagers](NodeManagerRegistration.md). Runtime NodeSets follow those rules, and the built-in runtime NodeSet manager already implements the `INodeManagerReloadParticipant` contract that reload requires.

### Shadow reload

`ShadowReloadRuntimeNodeSetAsync` (backed by `INodeManagerLifecycle.ShadowReloadAsync`) replaces a live registration the same way `ReloadRuntimeNodeSetAsync` does, but without the active-monitored-item guard:

```csharp
public async ValueTask ShadowReloadAsync(CancellationToken ct)
{
m_registration = await lifecycle.ShadowReloadRuntimeNodeSetAsync(
m_registration!,
new RuntimeNodeSetOptions
{
Sources = [RuntimeNodeSetSource.FromFile("Models/MyMachine.NodeSet2.xml")]
},
ct);
}
```

The replacement generation is prepared and published through the same transactional prepare/publish/commit/rollback path as `ReloadAsync`, so a failure during preparation, publication, or the routing switch leaves the current generation fully active and cleans up the replacement, exactly as a normal reload does. Once committed, every new service request is atomically routed to the replacement generation, including for namespaces the current and replacement generations share.

The current generation is not torn down immediately. It is moved to the same retired-generation bookkeeping used for an ordinary reload, but its existing monitored items and any request or continuation point that already captured it keep being served by it, unaffected by the routing switch. The retired generation is disposed automatically, without deleting any client subscription, once its monitored items and in-flight state drain; a later lifecycle operation (or shutdown) opportunistically retries that cleanup until it succeeds. `ShadowReloadAsync` returns the replacement `NodeManagerRegistration` immediately and invalidates the current handle for further lifecycle mutations, the same as `ReloadAsync`.

Use `ShadowReloadAsync` when a model update must take effect for new requests without waiting for existing subscriptions to unsubscribe first; use the fail-closed `ReloadAsync` when a stale generation must never remain reachable, even briefly, for already-open monitored items.

### Immediate reload

`ImmediateReloadRuntimeNodeSetAsync` (backed by `INodeManagerLifecycle.ImmediateReloadAsync`) performs the same atomic replacement but does not retain the previous generation until monitored items drain. After requests that already captured the old routing generation finish, every affected data-change monitored item is made publishable with `BadNodeIdUnknown`, event monitored items stop producing events, continuation points are invalidated, and the old NodeManager is disposed. The subscription and monitored-item records remain available so clients can receive the status and delete or recreate the affected items.

Use immediate reload only when continuity through the previous generation is not required. Durable monitored items are not eligible for immediate retirement because their terminal state would have to survive restart; choose shadow reload for any generation that owns them.


## Quick-start examples

### Single file
Expand Down
Loading
Loading