Skip to content

Model Server.ServerRedundancy via generated subtype instances (#3981) - #9

Merged
marcschier merged 3 commits into
nodestatestoragefrom
marcschier/3981-redundancy-subtype-instances
Jul 10, 2026
Merged

Model Server.ServerRedundancy via generated subtype instances (#3981)#9
marcschier merged 3 commits into
nodestatestoragefrom
marcschier/3981-redundancy-subtype-instances

Conversation

@marcschier

@marcschier marcschier commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Description

Refactors the Server.ServerRedundancy address-space modeling to materialize the correct generated subtype instance for the configured RedundancySupport mode instead of keeping a single base ServerRedundancyState, mutating its TypeDefinitionId, and adding the mode-specific children (CurrentServerId / ServerUriArray) via hand-written PropertyState construction.

Server.ServerRedundancy is now exposed as:

  • TransparentRedundancyType (TransparentRedundancyState) for Transparent — with the generated CurrentServerId,
  • NonTransparentRedundancyType (NonTransparentRedundancyState) for Cold/Warm/Hot/HotAndMirrored — with the generated ServerUriArray,
  • the base ServerRedundancyType for None.

The mode-specific members come from the generated information model rather than hand-built PropertyState nodes, and no hardcoded numeric redundancy-type NodeIds remain (ObjectTypeIds.* are used throughout). The well-known instance NodeIds (Server_ServerRedundancy_RedundancySupport, _RedundantServerArray, _CurrentServerId, _ServerUriArray) and values are preserved when the node is promoted to the subtype.

What changed

Generic core primitive (Opc.Ua.Server)

  • New AsyncCustomNodeManager.ReplacePredefinedInstanceSubtypeAsync(...), exposed via its own IPredefinedNodeSubtypeReplacer capability interface (documented in Docs/CoreNodeManagerVsCustomNodeManager2.md). It replaces a registered predefined instance node with a differently-typed instance (e.g. a generated subtype), preserving the node's identity (NodeId, BrowseName, parent), copying overlapping children's NodeIds and values by BrowseName, assigning caller-supplied well-known NodeIds to subtype-only children, swapping the address-space index, and emitting a ModelChange. It is generic and reusable beyond redundancy, and builds on the source-generator-provided typed CreateInstanceOf<Type> factories.

Server redundancy (Opc.Ua.Redundancy.Server)

  • New injectable ServerRedundancyController / IServerRedundancyController with:
    • the single-source RedundancySupport → ObjectTypeIds.* mapping (GetTypeDefinitionId),
    • a real runtime ChangeModeAsync(mode) that re-materializes Server.ServerRedundancy as the new subtype in place and raises a ModelChange so connected clients observe the new type definition/members.
  • ServerRedundancyStartupTask is now a thin delegate to the controller; the DI registration wires the controller and IServerRedundancyController.

Core DiagnosticsNodeManager

  • Removed AddServerRedundancyStringProperty / AddServerRedundancyStringArrayProperty and the dynamic ApplyServerRedundancyTypeDefinition mutation; keeps only the generated AddRedundantServerArray optional-child helper on the base node.

Design notes

  • The solution intentionally leverages the source generator (typed CreateInstanceOf<Subtype> factories, generated subtype state classes, generated AddRedundantServerArray, ObjectTypeIds/VariableIds, and the generic activator-based NodeStateFactory dispatch). It is OK to break back-compat here as the redundancy area is new in 2.0.
  • The base generated Server model registers CurrentServerId/ServerUriArray as orphaned loose predefined nodes (no parent); the promotion adopts the mode's member as a typed subtype child at its well-known NodeId and drops the other mode's member.

Note: this branch is stacked on the unmerged OPCFoundation#3918 (base
odestatestorage) and also carries the sample-image containerization work for OPCFoundation#3984 (Dockerfiles + docker-image.yml matrix). Both will be split/rebased onto master once OPCFoundation#3918 lands.

Related Issues

Testing

  • Opc.Ua.Redundancy.Server.Tests: full suite green (492/492 on net10.0), including new subtype/browse-model assertions and a runtime mode-change test.
  • Opc.Ua.Server.Tests: new ReplacePredefinedInstanceSubtypeAsync unit tests (identity/child-NodeId preservation, argument validation).
  • Opc.Ua.InformationModel.Tests RedundancyModelTests conformance: green.
  • Builds green on net10.0 and net48.

Checklist

  • I have signed the CLA and read the CONTRIBUTING doc.
  • I have added tests that prove my fix is effective or that my feature works and increased code coverage.
  • I have added all necessary documentation.
  • I have verified that my changes do not introduce (new) build or analyzer warnings.
  • I ran all tests locally using the UA.slnx solution against at least .net framework and .net 10, and all passed.
  • I fixed all failing and flaky tests in the CI pipelines and all CodeQL warnings.
  • I have addressed all PR feedback received.

…ndation#3981)

Expose Server.ServerRedundancy as the correct generated subtype (TransparentRedundancyState / NonTransparentRedundancyState / ServerRedundancyState) for the configured RedundancySupport mode, with mode-specific children (CurrentServerId / ServerUriArray) coming from the generated model instead of hand-written PropertyState construction. No hardcoded numeric redundancy type NodeIds remain.

- Add generic core primitive AsyncCustomNodeManager.ReplacePredefinedInstanceSubtypeAsync (+ IDiagnosticsNodeManager) that swaps a predefined instance node for a differently-typed instance, preserving identity, well-known child NodeIds and values, and emitting a ModelChange.

- Add ServerRedundancyController (IServerRedundancyController) with runtime ChangeModeAsync + RedundancySupport->ObjectTypeIds mapping; ServerRedundancyStartupTask now delegates to it.

- Simplify DiagnosticsNodeManager: drop hand-written CurrentServerId/ServerUriArray helpers and dynamic TypeDefinitionId mutation.

- Tests: subtype/browse-model assertions incl. runtime mode change; core primitive unit tests.
Comment thread Docs/HighAvailability.md Outdated
Copilot AI added 2 commits July 10, 2026 15:22
…PubSub samples to ghcr (OPCFoundation#3984)

- Add Dockerfiles for ConsoleLdsServer, MinimalBoilerServer, MinimalCalcServer, PumpDeviceIntegrationServer, McpServer (aspnet base for HTTP/SSE), and ConsoleReferencePubSubClient (root-context build, net10.0, PublishAot=false).

- Rewrite .github/workflows/docker-image.yml into a matrix that builds and pushes all 10 sample images (refserver, ldsserver, boilerserver, calcserver, pumpserver, mcpserver, redundantserver, redundantclient, redundantpubsub, pubsubclient) to ghcr on the existing ubuntu-latest runner, with per-image gha build cache scopes and fail-fast disabled.

- Document the additional images in Docs/ContainerReferenceServer.md.
…ment (OPCFoundation#3981)

- Move ReplacePredefinedInstanceSubtypeAsync into its own capability interface IPredefinedNodeSubtypeReplacer implemented by AsyncCustomNodeManager; remove it from IDiagnosticsNodeManager. ServerRedundancyController now resolves the capability via 'server.DiagnosticsNodeManager as IPredefinedNodeSubtypeReplacer'.

- Document the capability (usage example, when/when-not to use, reuse candidates, and the fluent-API rationale) in Docs/CoreNodeManagerVsCustomNodeManager2.md.

- Trim the user-facing ServerRedundancy subtype paragraph and reword the runtime paragraph to focus on IServerRedundancyController.ChangeModeAsync in Docs/HighAvailability.md.
@marcschier
marcschier marked this pull request as ready for review July 10, 2026 14:21
@marcschier
marcschier merged commit b718628 into nodestatestorage Jul 10, 2026
@marcschier
marcschier deleted the marcschier/3981-redundancy-subtype-instances branch July 10, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants