Hi I would like to know how to handle (correctly) resubscribing with OPC UA milo. Currently I use this code to create subscribtion:
private CompletableFuture<DataValue> subscribe(NodeId nodeToSubscribe, double samplingInterval, Consumer<DataValue> onChangeDo){
CompletableFuture<DataValue> result = new CompletableFuture<>();
try{
//sets parameters of subscription
ManagedSubscription subscription = ManagedSubscription.create(client, samplingInterval);
subscription.setDefaultSamplingInterval(samplingInterval);
subscription.setDefaultQueueSize(uint(10));
//adds "onChange" action
ManagedDataItem managedDataItem = subscription.createDataItem(nodeToSubscribe, item -> item.addDataValueListener(onChangeDo));
//wait till first value was read
ManagedDataItem.DataValueListener listener = managedDataItem.addDataValueListener(result::complete);
result.whenComplete((v,e) -> managedDataItem.removeDataValueListener(listener));
} catch (UaException e){
result.completeExceptionally(e);
}
return result;
}
But whenever the server is restarted or the connection between client and server goes down than the subscription is not working.
I could add session activity listener and when ever the connection goes down clear the subscription manager like that (code between stars).
addSessionActivityListener(new SessionActivityListener(){
@Override
public void onSessionActive(UaSession session) {
log.info("Connecting PLC with IP address {}",ipAddress);
setConnectionStatus(ConnectionStatus.CONNECTED);
**subscribeAll();**
}
@Override
public void onSessionInactive(UaSession session) {
log.info("Disconnecting PLC with IP address {}",ipAddress);
setConnectionStatus(ConnectionStatus.DISCONNECTED);
**uaClient.getSubscriptionManager().clearSubscriptions();**
}
});
But maybe there is better way how to handle this. All my code can be found here GitHub
UPDATED: Based on Kevin Harron's reply I can see that it should be done automatically but I am receiving this every time the server is disconnected (my log for subscription and statusCode):
ON SUBSCRIPTION TRANSFER FAILED: subscription org.eclipse.milo.opcua.sdk.client.subscriptions.OpcUaSubscription@3f344a79, status code StatusCode{name=Bad_ServiceUnsupported, value=0x800B0000, quality=bad}
As you can see, there is probably problem, that server doesn't support transfer of subscription. Kevin advised me that this should be handled using SubscriptionListener::onSubscriptionTransferFailed
so I implemented it like this:
uaClient.getSubscriptionManager().addSubscriptionListener(new UaSubscriptionManager.SubscriptionListener() {
@Override
public void onSubscriptionTransferFailed(UaSubscription subscription, StatusCode statusCode) {
uaClient.getSubscriptionManager().clearSubscriptions();
subscribeAll();
}
It seams to work but I would like to know if this is the best way or I missed something. Thanks all for answers.
The correct approach is mostly to do nothing - all of the details of reconnecting and resubscribing are handled automatically.
The only case you need to handle is when the subscriptions were unable to be transferred after a new session was created. Implement SubscriptionListener::onSubscriptionTransferFailed
to re-create any subscription this callback indicates has failed to transfer.
There's not really any other scenario where you should be manually clearing and re-creating your subscriptions. The onPublishFailure() callback is largely informational and does not require action. onSessionActive() and onSessionInactive() are purely informational and do not require any action from you.