OPC UA Subscription Transfer: Preserve Monitoring Across Client Session Replacement

TransferSubscriptions moves an existing Subscription and its MonitoredItems to the requesting Session when the server accepts the identity and resource checks. Treat the returned result for each Subscription as the ownership decision. Opening a replacement Session, knowing a Subscription identifier or receiving one successful service response does not prove that every requested Subscription moved.

This guide pins OPC UA Part 4, Services, version 1.05.07, sections 5.14.7 and 6.7. It focuses on transfer authorization, ownership and initial-value behavior. SecureChannel renewal and the detailed Republish loop are separate procedures. An original reduced state model was executed locally; no authenticated server, SDK or network transfer was tested.

Confirm that Session replacement is actually needed

The reconnect procedure first attempts to activate the existing Session through a replacement SecureChannel. Transfer becomes relevant when a new Session is needed, or when an explicitly designed takeover moves monitoring to another Session. Creating new Subscriptions immediately can produce duplicate monitoring while the old ones still exist.

Keep the original Subscription identifiers, monitored-item client-handle mappings and receive ledgers in a bounded recovery record. A transferred Subscription preserves its identity; a newly created one requires a new local generation even if the server later reuses a numeric identifier.

Before transfer, stop competing recovery owners from independently recreating the same monitoring set. One application coordinator should decide which Session is receiving the transfer, which requests are pending and when normal delivery is admitted.

Session A owns Subscriptions7 and8. Session B requests both. The server accepts7 and denies8. Only7 moves to B, while8 remains with A; the old Session receives Good_SubscriptionTransferred for the accepted transfer. Initial values use queued or last-sent data, not a guaranteed fresh snapshot.
Transfer results are per Subscription. A mixed response must not become an all-or-nothing ownership claim.

Validate identity without weakening security

The request header identifies the destination Session. For a non-anonymous user, the server validates that the client of that Session operates on behalf of the same ClientUserId as the existing owner. A familiar application name or matching human-readable username is not a substitute for the server’s authenticated identity decision.

For anonymous use, this version specifies matching ApplicationUri for the old and new Session and a MessageSecurityMode of Sign or SignAndEncrypt. Qualify that separate branch explicitly if the product supports it. Do not assume anonymous transfer over a channel with no message security is equivalent.

The local model exercised same-user acceptance, different-user rejection, same-application signed anonymous acceptance, changed-application rejection and insecure anonymous rejection. These are synthetic policy branches. They do not establish certificate validation, user-token equivalence or an actual server’s supported profile.

Handle each operation result

TransferSubscriptions returns results in the same order as the requested identifiers. Associate every result with that exact input slot, including duplicates or application configuration mistakes that should have been rejected before submission.

Observation Engineering interpretation Next action
Successful transfer Destination owns that Subscription Adopt its mapping and recovery state
Bad_UserAccessDenied Transfer identity is not accepted Investigate identity; do not weaken security
Bad_SubscriptionIdInvalid Requested Subscription is unavailable in this context Use explicit recreation policy
Bad_TooManySubscriptions Destination Session capacity is exhausted Correct allocation or reduce the intended set
Bad_NothingToDo Subscription already belongs to this Session Reconcile local state with confirmed ownership

The service can also reject a destination whose client profile is insufficient. Keep service-level failures separate from per-Subscription failures. A lost response creates uncertainty; do not automatically delete the old Subscription or create another one before the SDK’s documented recovery process establishes the outcome.

Retire the previous owner deliberately

For a successful transfer, the server sends Good_SubscriptionTransferred in a StatusChangeNotification to the old Session. Route that signal to the old consumer’s lifecycle owner. It should stop treating the moved Subscription as its active source and should not start a competing recreation loop.

That notification is evidence about the old owner’s state, while the destination’s transfer result controls its own adoption. Asynchronous arrival can make the two observations occur in different orders. Tag callbacks with local Session and ownership generations so delayed old-path work cannot mutate the new owner’s current state.

Do not call DeleteSubscriptions from a generic old-session cleanup path using identifiers already transferred away. Clean up only resources the client still owns, and use the chosen SDK’s documented close behavior. An ownership table is more reliable than assuming every resource created by one connection must still belong to it.

Interpret sendInitialValues precisely

With sendInitialValues true, the first Publish response or responses after transfer include values for data MonitoredItems in Reporting mode. If an item has a queued value, its next queued value is sent; otherwise its last sent value is repeated. This parameter does not request an atomic fresh acquisition across all nodes.

With false, delivery contains value changes since the last Publish response was sent. The option applies to attribute-change monitoring, not a universal replay request for Events. Preserve timestamps, status and item identity when comparing transferred delivery with the previous owner’s cache.

In the hypothetical fixture, one Reporting item has queued values 71 and 72, another has no queue and last sent value 80, and a Sampling item has value 90 queued. The initial projection is 71 and 80. It is neither 72 and 80 nor a new read of every item. The Sampling item is excluded from that Reporting-only projection.

Qualify recovery and ownership together

  1. Create a small monitored set with known client handles and preserve its receive ledger.
  2. Replace the Session through the supported recovery path and transfer under the same accepted identity.
  3. Capture ordered per-Subscription results and the old Session’s transfer notification.
  4. Repeat with a mixed batch containing a valid and invalid identifier; verify only successful entries are adopted.
  5. Exercise both initial-value settings with a queued item, an empty queue and a non-Reporting item.
  6. Test unauthorized identity, destination capacity, delayed callbacks and a response lost after server processing.

The executed model checked ownership, identity branches, initial-value selection, unchanged sequence state and the old-owner signal. It did not simulate mixed wire responses or uncertain network completion. Server acceptance testing must establish those behaviors and retain any notification gaps separately. Successful transfer preserves monitoring objects; it does not prove that every intervening process change survived.

Similar Posts