Professional OPC
Development Tools

logos

Online Forums

Technical support is provided through Support Forums below. Anybody can view them; you need to Register/Login to our site (see links in upper right corner) in order to Post questions. You do not have to be a licensed user of our product.

Please read Rules for forum posts before reporting your issue or asking a question. OPC Labs team is actively monitoring the forums, and replies as soon as possible. Various technical information can also be found in our Knowledge Base. For your convenience, we have also assembled a Frequently Asked Questions page.

Do not use the Contact page for technical issues.

EasyDAClient fails to release connection after unsubscribe call.

More
28 Aug 2023 16:43 #12037 by ncorbett
Hello, thanks again for the response.

With the information you have provided we have been able to synchronize our use of the subscribe and unsubscribe methods. Using the suggested hold periods has enable us to close down the connections in a timely manner. We introduced our own delay mechanism to ensure the connections are released.

This has allowed us to shutdown in a controlled and timely manner.

Again, thank you for support. It has been very helpful.

Please Log in or Create an account to join the conversation.

More
17 Aug 2023 10:12 #12024 by support
Hello.

If the IsKnownItemSubscriptionHandle behaves like you described, it would be a bug on our side. I will look into it, but please be patient this time, I need to prioritize with other tasks, plus I will be out of office for 1 week soon. I will post an update here when I have more to say.

Unfortunately we provide no way (in OPC DA) for you to observe the disconnections/detect when it has been finalized. The sleeping approach is the only one usable.

With subscriptions, make sure that you shorten both ItemDetach and Serverdetach hold periods, if you want it to proceed quickly.

Best regards

Please Log in or Create an account to join the conversation.

More
16 Aug 2023 17:19 #12018 by ncorbett
Hello,

thank you for the prompt response.

The information you have provided has been very useful and has allowed us to explore the issue further.


Fixing the calling of SubscribeXXX & UnsubscribeXX:
We have been able to ensure the SubscribeXXX and UnsubscribeXX methods are called in order with no possibility of these being enqueued out of order. We do this by waiting for the EasyDAItemChanedEventHandler registered with ItemChanged to be called as a consequence of the SubscribeXXX call before allowing the UnsubscribeXXX being called.



This allowed us to investigate our Unsubscribe, Dispose use.

Our solution now:
• Calls UnsubscribeAllItems() on the EasyDAClient : Where there is no possibility of it clashing with a Subscribe.
• Unregisters the EasyDAItemChanedEventHandler from the ItemChanged on the EasyDAClient.
• Call Dispose() on the EasyDAClient object.
• Dispose of the container object, terminating the thread in which it is running.

This still results in the client connection remaining open on the server, and the subscriptions remaining active.

We added a Thread.Sleep(5 seconds) to the source after calling UnsubscribeAllItems() and so delaying the disposal of the EasyDAClient and the containing object.
As a result we did see the subscriptions on the server being released, and the connection released in a timely manner.

From this we have deduced that we need to allow time for the EasyDAClient UnsubscribeAllItems() and the subsequent disposal of the EasyDAClient and the container to concluded its unregistering of the subscription from the server and closing the connection.

We do not wish to include an arbitrary sleep in our solution and wish to determine in code when the subscription has been released and the connection released so we may then dispose of the EasyDAClient and its container.

You mentioned IsKnownItemSubscriptionHandle() indicates the liveliness of the subscriptions, and so we have attempted to use this an indication of when the UnsubscribeAllItems() has been concluded.

We did this by maintaining a list of handle Ids returned from the SubscribeXXX, then using IsKnownItemSubscriptionHandle() to check these handles exist after our call to UnsubscribeAllItems().

Calls to IsKnownItemSubscriptionHandle(correctHandleId) returns true before a call to UnsubscribeAllItems() and still returns true after the call to UnsubscribeAllItems()

We then attempted to use: GetItemSubscriptionArguments(correctHandleId). Calls to this return a valid object before a call to UnsubscribeAllItems() and throw an exception stating unknown hander after a call to UnsubscribeAllItems().

This suggested we could use the fact that GetItemSubscriptionArguments(correctHandleId) throws after a call to UnsubscribeAllItems() to indicate that the subscriptions have been released and the connection could be released.

However even after using GetItemSubscriptionArguments() as an indication that the subscriptions are released, if we immediate call dispose on EasyDAClient() and dispose its container the subscriptions on the server and its connection remain.

So to allow the subscriptions to be released and the connection to be released we need to add a delay after the call to the EasyDAClient.Dispose() before releasing the owner of EasyDAClient. We proved that by adding a thread sleep after the call to EasyDAClient.Dispose().

To answer your question:

We use a kepware test server, which provides its own diagnostics output where we can observe the connection is still active and the subscriptions are still registered, in the diagnostic logs.

All software is running on the same host including the server so there are no networking issues.

I appreciate you referencing the OPC UA and its connection status support, however at this time if we can resolve this disposal timing issue our current solution would suffice.

In summary:

Theres an issue with IsKnownItemSubscriptionHandle()
Calling IsKnownItemSubscriptionHandle(previsoulyExistingHanlderID) after UnsubscribeAllItems() incorrectly returns true.
Calling GetItemSubscriptionArguments(previsoulyExistingHanlderID) after UnsubscribeAllItems() correctly throws the unknown handler exception contradicting the same call to IsKnownItemSubscriptionHandle() illustrated above..

We need to deterministically delay the disposal and release of the container (and thread) in which EasyDAClient exists to allow time for the EasyDAClient to complete its unsubscribe action on the server and release its connection.
How can we determine when EasyDAClient has concluded its unsubscribe and connection release so we can safely dispose its container and thread context?
Is there any artefact with EasyDAClient on which we can block or poll to determine when we can release the container resources?
We appreciate a Thread.Sleep(some arbitrary time) will work but it's not ideal.

Again we really appreciate your support.

Kind Regards,

ncorbett.

Please Log in or Create an account to join the conversation.

More
15 Aug 2023 18:21 #12002 by support
Hello.
This issue I am unable to reproduce.

Here is the information you asked for:

You can think of any SubscribeXXXX, UnsubscribeXXXX and "change subscription" calls (and, the call to UnsubscribeAllItems made by Dispose) as being put into a queue. So, your code ("foreground") just enqueues the requests (and allocated and deallocates the handles). Then there is code in "background" that dequeues and executes them - always in the order they were enqueued, and it always waits before the previous one finalizes execution before it proceeds to the next one.

If you are calling SubscribeXXXX and UnsubscribeXXXX from separate, unsynchronized threads, then it might be impossible to tell - already on the "foreground" - in which order they will be enqueued and thus executed - which may be a problem, yes. However, if the final (last) call being made is the Dispose, which effectively does UnsubscribeAllItems too, it should "resolve" it.

There are no logs to help with this. Your code can detect what has been done on the foreground, for a particular item subscription, using IEasyDAClient.IsKnownItemSubscriptionHandle method. But the true status of the that subscription, on the "background", may be different at that point.

The code on the background can actually take long (very long) time to execute. This is because COM/DCOM methods calls needed to "close" the connection (which involves things like decreasing the object reference counts in the server) are synchronous (blocking) in their nature. If there are network problems, or simply the servers blocks in the method, there is nothing the client do. For calls to remote objects that are no longer accessible, DCOM will eventually time out, but the times involved are long (one of the famous DCOM timeout is 6 minutes).

This possibility of blocking is one of the reasons why we made the "foreground" non-blocking; users really hated when their API calls blocked.
However, while the "close" is still in progress, shutting down the process in a clean manner is impossible.

We could think of adding something to indicate the true connection status to your code (we have that for OPC UA), but it is not in plans.

All this said, if you do not have network or OPC server-side problems, the shutdown should actually proceed quite quickly. What tool do you use to monitor that the connection to the server is still open? Could it be that the server blocks in processing the "close"?

Regards

Please Log in or Create an account to join the conversation.

More
15 Aug 2023 09:05 #11995 by ncorbett
Good Morning,

Software version: OpcLabs.QuickOpc Nuget Package: 5.71.123

We are using an EasyDACLient.

We appreciate with EasyDAClient the connection is maintained on demand where it will be established by the library to support each of the subscription, write and read activities.

We have the requirement to release the connection and we do this by:
• Ensuring no calls are made to read or write methods.
• Unsubscribe calling UnsubscribeAllItems()

Scenario:
We are using an EasyDAClient instance to connect with a Server where we do the following:

a) Register and verify our license using the RegisterManagedResourceWithExistenceCheck()
This is successful.

a) Register a callback with ItemChanged for change notifications for subscriptions.

a) Subscribe for change notifications using SubscribeMultipleItems(…)

In this scenario at this point we have an immediate need to close the connection. The service in which the connection is established is closing.

In this case we:
a) Ensure no read or write calls are made.
b) We call UnsubscribeAllItems() on the EasyDAClient.
c) We unregister the callback handler from ItemChanged on the EasyDAClient.
d) We call Dispose() on the EasyDAClient object.

At this point we expect the Connection with the server to be released and all activity with the server to cease.

However we observe:
• The connection at the server remains open.
• It appears that the subscription with the server remains.
• It takes approximately 9min for the connection to be released at the server.

Please note:
• The call to SubscribeMultipleItems() appears successful. No error or exceptions can be seen.
• The call to UnsubscribeAllItems() appears successful. No error or exceptions can be seen.
• The call to UnsubscribeAllItems() is made after SubscribeMultipleItems() albeit the call to UnsubscribeAllItems() is made before any notifications are received or any read/write actions are performed.

We suspect that the UnsubscribeAllItems() is not being serviced correctly possibly due it is being made before SubscribeMultipleItems() has been serviced completely, and as a consequence the subscription with the server is not been released, which is then preventing the connection to the server from being released.

We have no evidence of this.

Questions:
• Are there any logs that can be enabled for the EasyDAClient that would allow us to observe the internal behaviour of the QuickOPC client library in this scenario and appreciate why the subscriptions and connection is not being released as expected?
• Are there any race conditions between calling SubscribeMultipleItems() and UnsubscribeAllItems() that we should be aware of?
• If there are race conditions between calling calling SubscribeMultipleItems() and UnsubscribeAllItems() is there any state (synchronisation objects) on which we can wait that indicates SubscribeMultipleItems() has completed and it is now safe to call UnsubscribeAllItems()?

Kind regards, ncorbett.

Please Log in or Create an account to join the conversation.

Moderators: support
Time to create page: 0.079 seconds