Professional OPC
Development Tools

logos

Random Disconnect from OPC server

More
08 Apr 2019 15:53 #7313 by Olya
Hi,
Thank you very much for your support. We will try the proposed solution.

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

More
08 Apr 2019 15:11 #7312 by support
Hello.

I tried to reproduce the issue again. I still was not able to reproduce the "inability to reconnect" after > 10 minutes. But, on the other hand, I was able to get "Read not completed..." errors, if I continued increasing the number of threads, even during normal operation.So, I went to analyze what is happening, and here is the outcome:

As the number of threads increases, two aspect of the load on the component increase:
1. The "basic" and obvious increase is in the fact that total number of reads per unit of time increases. So, more needs to be processed on the client, through the network, and on the server. The consequence is that the time to complete ReadMultipleItems may increase as well.
2. When the reads and invoked by separate threads on separate EasyDAClient instances, the component sees them as one incoming stream of item read requests, and may do sub-optimal job in putting requests together to achieve highest performance (in OPC, it is desirable to "group" multiple requests into a single operation, if possible). Precisely explaining this would require long discussion of the internal implementation details of EasyDAClient, so for now it should suffice that there a recommendation to overcome this - see further below.

It is possible that the problem with the reconnection is just an odd manifestation of the same thing. So, I went to modify your test program to see if I can make it work better. It seems counter-intuitive, but it is actually better to use just one common EasyDAClient instance (at least for the Read operations). Doing so eliminates the possible performance degradation described in #2 above. My resulting code looks like this:
namespace OpcLabsTest
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using OpcLabs.EasyOpc;
    using OpcLabs.EasyOpc.DataAccess;
    using OpcLabs.EasyOpc.DataAccess.OperationModel;
 
    public class Program
    {
        static public void Main(string[] args)
        {
            EasyDAClient.SharedParameters.TopicParameters.SlowdownWeight = 0.0f;
            EasyDAClient.SharedParameters.TopicParameters.SpeedupWeight = 0.0f;
 
            OpcClient.InstanceParameters.Mode.AllowAsynchronousMethod = false;
            OpcClient.InstanceParameters.UpdateRates.ReadAutomatic = Timeout.Infinite;
            OpcClient.InstanceParameters.UpdateRates.WriteAutomatic = Timeout.Infinite;
 
            Subscribe();
 
            for (int i = 0; i < 500; ++i)
            {
                Task.Run(() => PullingCollectorThread(i));
                Thread.Sleep(500);
            }
 
            Console.WriteLine("Test started");
            Console.ReadKey();
        }
 
        static private void PullingCollectorThread(int id)
        {
 
            while (true)
            {
                var cache = new List<DAVtqResult>();
                DAVtqResult[] results = OpcClient.ReadMultipleItems(new[]
                        {
                    GetDATagArguments("WTG10.Int1"),
                    GetDATagArguments("WTG10.Alm"),
                    GetDATagArguments("WTG10.Bool"),
                    GetDATagArguments("WTG10.Int2"),
                    GetDATagArguments("WTG10.Int4"),
                    GetDATagArguments("WTG10.String1"),
                    GetDATagArguments("WTG10.Time"),
                    GetDATagArguments("WTG10.Time1"),
                    GetDATagArguments("WTG1.Alm"),
                    GetDATagArguments("WTG1.Bool"),
                    GetDATagArguments("WTG1.Int1"),
                    GetDATagArguments("WTG1.Int2"),
                    GetDATagArguments("WTG1.Int4"),
                    GetDATagArguments("WTG1.String1"),
                    GetDATagArguments("WTG1.Time"),
                    GetDATagArguments("WTG1.Time1"),
                });
 
                if (results.First().Succeeded)
                {
                    Console.WriteLine($"Test #{id} WTG10.Int1: {results[0].Vtq.Value}({results[0].Vtq.Quality})");
                }
                else
                {
                    Console.WriteLine($"Test #{id} Error happened: {results[0].Exception.Message}");
                }
 
                cache.Add(results[0]);
                Thread.Sleep(2000);
            }
        }
 
        static private void Subscribe()
        {
            var opcClient = new EasyDAClient();
            opcClient.ItemChanged += OnSubscriptionDataChanged;
 
            const string itemId = "WTG10.Int1";
            opcClient.SubscribeMultipleItems(
                new[] {
                    new EasyDAItemSubscriptionArguments(
                        new DAItemGroupArguments(
                            ServerDescriptor,
                            new DAItemDescriptor(itemId),
                            new DAGroupParameters(requestedUpdateRate:2 * 1000, percentDeadband: 0),
                            state:itemId)
                    )});
        }
 
        static private void OnSubscriptionDataChanged(object state, EasyDAItemChangedEventArgs args)
        {
            Console.WriteLine(args);
        }
 
        static private DAReadItemArguments GetDATagArguments(string tag)
        {
            return new DAReadItemArguments(ServerDescriptor, tag);
        }
 
        static private readonly EasyDAClient OpcClient = new EasyDAClient();
        static private readonly ServerDescriptor ServerDescriptor = "opcda://10.1.0.6/Matrikon.OPC.Simulation.1";
    }
}
With this, I was able to get many more threads working without problems when the connection was up (and also could not get it to *not* reconnect after it was down, but that I was never able to reproduce anyway).

I therefore suggest that you "copy back" the principles of the code above to your production program - main things to watch out for are:
a) The settings made to static and instance properties of the EasyDAClient at the beginning of the Main() functions, and
b) The usage of common EasyDAClient instance for the reads.

Regards
The following user(s) said Thank You: Olya

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

More
03 Apr 2019 09:22 #7293 by Olya
Hi,
1) The number of threads using EasyDAClient in our main application is dynamic (depends on some configurations). But normally it should not be more than a hundred.
2) In the test application, it was a Debug configuration that targets an AnyCPU running under 32-bit process. In the main application, we are going to target x64 platforms.
3) I observed it when running without the debugger.
4) It is still "Read not completed ..."

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

More
02 Apr 2019 05:13 #7288 by support
Hello,
I could not reproduce it so far - not even after waiting over 10 minutes.

Can you please answer some additional questions:
1. How many items and threads (I mean threads that use EasyDAClient) are there in the real program? I understand that in the sample code, it is artificially high, for the purpose of achieving the repro - but obviously there are always limits as to how far one can go.
2. In the main project properties, are you targeting x86, x64, or AnyCPU? If AnyCPU, are you running it under 32-bit or 64-bit process?
3. Do you observe the issue when running with the debugger, without the debugger, or in both cases?
4. With the newest build of QuickOPC, are you still getting "Read not completed..."? If not, what are the symptoms (e.g. other error, or does it block forever in the ReadMultipleItems, etc.

Thank you

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

More
01 Apr 2019 12:45 #7287 by Olya
Hello,
Is there any news on this one?

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

More
20 Mar 2019 14:38 #7241 by Olya
Hi Again. We tested this issue with the latest build and it is still reproducible. It is much easier to reproduce if you increase the number of pulling threads and wait at least 10 minutes before reconnecting to the network.
It is really important to us to make this work since some of our customers have poor network quality between our system and OPC server and we need to be sure that this will not result in some significant data loss.
It would be also helpful if you can advise us in which direction should we dig to find the cause. Can it be some system resources, network or COM configuration ... anything we can help with?

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

More
19 Mar 2019 15:20 - 19 Mar 2019 15:22 #7230 by support
My results are as follows:

I was not able to reproduce the issue, when using your code as it was, or with the first set of parameters.

The second set of parameters you have tried (with Isolated = true) indeed brings problems, although in my case I was able to get the data sometimes. But in this case, it in understandable. What happens is that if, as in this program, you have 501 EasyDAClient objects, with Isolated = false they all share one connection to the target OPC server, but with Isolated = true there are 501 connections to the servers, creating a very high load on the client, the network, and the server. There should be no need to "isolate" the connections in this way. The setting is meant a) for special where you truly need two connections to the same server, and b) for creating some libraries which want to be sure they are not influenced by possibly other things going on in the same process and using QuickOPC. In this case (b), however, you would create one EasyDAClient instance, set its Isolated to 'true', and use it at multiple places in the program - and not create the EasyDAClient instance inside each thread or routine.

Note that I have done the tests with recent build of QuickOPC 2018.3 (i.e. 5.54.1115.1).This build already has a fix for the other reported problem. The nature of the problem was either error messages about improper server response could have been issued, OR data updates from the server could have been "thrown away" - under rare circumstances, but quite unpredictable (it depended on memory allocation layout). So, in any case, please repeat your test with this recent build. Other than that, without having a reproducible case, I cannot proceed any further at the moment, sorry.

Regards
Last edit: 19 Mar 2019 15:22 by support.

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

More
18 Mar 2019 20:58 #7227 by support
I am setting the scenario up, with the code & configuration you have provided. Will let you know here once I have more information.

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

More
05 Mar 2019 15:12 - 09 Mar 2019 16:09 #7174 by Olya
Hi,

There are no Mode and UpdateRates properties in EasyDAClient.AdaptableParameters.

We have tried :
EasyDAClient.SharedParameters.TopicParameters.SlowdownWeight = 0.0f;
            EasyDAClient.SharedParameters.TopicParameters.SpeedupWeight = 0.0f;
 
            EasyDAClient.SharedInstance.InstanceParameters.Mode.AllowAsynchronousMethod = false;
            EasyDAClient.SharedInstance.InstanceParameters.UpdateRates.ReadAutomatic = Timeout.Infinite;
            EasyDAClient.SharedInstance.InstanceParameters.UpdateRates.WriteAutomatic = Timeout.Infinite;

with "Isolated" set to false. No changes in behavior. Still fails.

We also have tried:
EasyDAClient.SharedParameters.TopicParameters.SlowdownWeight = 0.0f;
            EasyDAClient.SharedParameters.TopicParameters.SpeedupWeight = 0.0f;
 
            EasyDAClient opcClient = new EasyDAClient();
            opcClient.Isolated = true; 
            opcClient.InstanceParameters.Mode.AllowAsynchronousMethod = false;
            opcClient.InstanceParameters.UpdateRates.ReadAutomatic = Timeout.Infinite;
            opcClient.InstanceParameters.UpdateRates.WriteAutomatic = Timeout.Infinite;

In the second case, it infinitely hangs without reconnection.
Last edit: 09 Mar 2019 16:09 by support.

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

More
05 Mar 2019 13:09 #7169 by support
Thank you for the details.
I will try to reproduce it on our side. However, due to business trip duties I cannot start on it sooner than in the end of the next week.

In the meantime, I'd like to ask you to try one more thing - Enhance your code similarly to this:
EasyDAClient.SharedParameters.TopicParameters.SlowdownWeight = 0.0f;
EasyDAClient.SharedParameters.TopicParameters.SpeedupWeight = 0.0f;
 
EasyDAClient.AdaptableParameters.Mode.AllowAsynchronousMethod = false;
EasyDAClient.AdaptableParameters.UpdateRates.ReadAutomatic = Timeout.Infinite;
EasyDAClient.AdaptableParameters.UpdateRates.WriteAutomatic = Timeout.Infinite;
These are static setting that needs to be done once, before any EasyDAClient instance is created.
The code would be slightly different if you are setting the Isolated property to 'true'; in that case, the last 3 parameters need to be set in the InstanceParameters of the EasyDAClient instance.

The settings are designed to switch off some parts of the internal logic that we have seen in the past to possibly cause problems.

Regards

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

Moderators: support
Time to create page: 0.228 seconds

      

 Recommend this on Google