etzel-mes commented on code in PR #27910:
URL: https://github.com/apache/camel/pull/27910#discussion_r4287647723


##########
components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java:
##########
@@ -683,6 +697,37 @@ public OpcUaClient getOpcUaClient() {
         }
     }
 
+    /**
+     * Deletes and creates the subscription of the current connection again, 
inside the existing session, and creates
+     * its monitored items again. Does nothing if the subscription no longer 
belongs to the current connection or has
+     * already been recreated since the given id was observed. Falls back to 
rebuilding the connection if this fails.
+     */
+    private void recreateSubscription(final OpcUaSubscription subscription, 
final Optional<UInteger> id) {
+        lock.lock();
+        try {
+            if (this.disposed || this.connected == null || 
this.connected.manager != subscription
+                    || !subscription.getSubscriptionId().equals(id)) {
+                LOG.debug("Subscription {} is stale or already recreated", 
id.orElse(null));
+                return;
+            }
+            try {
+                subscription.delete();
+            } catch (final UaException e) {
+                LOG.debug("Failed to delete subscription {}", id.orElse(null), 
e);
+                subscription.reset();
+            }

Review Comment:
   Agreed. With a closed connection it was worse than an orphan: the `reset()` 
and `create()` that followed waited for the session while holding `lock`, and 
with a producer on the connection that never ended (details in the main 
comment). The new version has no `reset()`. It creates the subscription again 
only when `deleteAsync()` returns `Good` or `Bad_SubscriptionIdInvalid`, that 
is, after Milo has reset the object itself in `applyDeleteResponse`. A lost 
connection or session is left to Milo's session recovery, and any other 
failure, such as a request timeout, rebuilds the connection through 
`handleConnectionFailure`, which closes the session together with the 
subscription. The `Bad_Timeout` path goes through the same code; there the 
delete completes without a service call, as you say.
   
   _Claude Code on behalf of etzel-mes_
   
   



##########
components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java:
##########
@@ -683,6 +697,37 @@ public OpcUaClient getOpcUaClient() {
         }
     }
 
+    /**
+     * Deletes and creates the subscription of the current connection again, 
inside the existing session, and creates
+     * its monitored items again. Does nothing if the subscription no longer 
belongs to the current connection or has
+     * already been recreated since the given id was observed. Falls back to 
rebuilding the connection if this fails.
+     */
+    private void recreateSubscription(final OpcUaSubscription subscription, 
final Optional<UInteger> id) {
+        lock.lock();
+        try {
+            if (this.disposed || this.connected == null || 
this.connected.manager != subscription
+                    || !subscription.getSubscriptionId().equals(id)) {
+                LOG.debug("Subscription {} is stale or already recreated", 
id.orElse(null));
+                return;
+            }
+            try {
+                subscription.delete();
+            } catch (final UaException e) {
+                LOG.debug("Failed to delete subscription {}", id.orElse(null), 
e);
+                subscription.reset();
+            }
+            subscription.create();
+            if 
(!subscription.createMonitoredItems().stream().allMatch(MonitoredItemServiceOperationResult::isGood))
 {
+                throw new UaException(StatusCodes.Bad_UnexpectedError, "Failed 
to create the monitored items again");
+            }

Review Comment:
   Done. The recreate clears `goodSubscriptions`, drops the monitored items 
that were reset with the subscription, and passes the subscriptions it held to 
`putSubscriptions`, so `goodSubscriptions` is rebuilt from the results. A node 
that cannot be monitored again is removed from the subscription and from 
`goodSubscriptions`, and is reported once to its consumer as a bad `DataValue` 
after `lock` has been released. Only a failed `create()` or a rejected service 
call rebuilds the connection. 
`nodeThatCannotBeMonitoredAgainIsReportedWithoutRebuildingTheConnection` 
deletes one of two monitored nodes on the embedded server before the 
subscription times out there, and checks that its consumer receives 
`Bad_NodeIdUnknown`, that the other node keeps delivering and that the 
`OpcUaClient` is the same instance. It fails with the first revision, which 
rebuilt the connection.
   
   _Claude Code on behalf of etzel-mes_
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to