opcua-asyncio icon indicating copy to clipboard operation
opcua-asyncio copied to clipboard

Timeout using sync client for recursive tag discovery

Open fshriver opened this issue 3 years ago • 1 comments

Describe the bug
I've written a function to recursively get all tags with no children under an OPC-UA node (so all atomic tags, effectively). It stays stable up to 100+ OPC-UA tags, however when I push it to 500+ it throws (apparently) a timeout error (see below error message). What's confusing is that, if I re-run the function once or twice, it will then recursively retrieve the tags just fine.

Because of the nature of my application, I have to run the OPC-UA client globally and have different threads call functions on the client, but none of them should interfere as I only ever work with one thread. I don't believe it's a problem with my use of threading directly, but rather some interaction between the asyncio and threading modules.

To Reproduce
The recursive function in question:

def get_tag_definitions(
    starting_node, tag_definitions, path='', search_string=''
):

    nodes = starting_node.get_children()

    for node in nodes:
        node_name = node.read_browse_name().to_string()

        if path == '':
            delimiter = ''
        else:
            delimiter = ','

        node_path = path + delimiter + node_name

        if len(node.get_children()) == 0:
            node_id = node.aio_obj.nodeid.to_string()

            tag_definitions[node_id] = {
                'node_id': node_id
            }
            print(
                'Found relevant node: {}'.format(tag_definitions[node_id])
            )
        else:
            get_tag_definitions(
                node,
                tag_definitions,
                path=node_path,
                search_string=search_string,
            )

It's initialized with a lower-level directory within the OPC-UA server (not the root node) and an empty dictionary.

Resulting error message:

Exception in thread Thread-2:
 Traceback (most recent call last):
   File "/usr/lib/python3.9/asyncio/tasks.py", line 492, in wait_for
     fut.result()
 asyncio.exceptions.CancelledError
 The above exception was the direct cause of the following exception:
 Traceback (most recent call last):
   File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
     self.run()
   File "/usr/lib/python3.9/threading.py", line 892, in run
     self._target(*self._args, **self._kwargs)
   File "/home/fshriver/test/test.py", line 155, in init_func
     dataclient.find_all_tags(profile_name, device_name)
   File "/home/fshriver/test/opc_ua_client.py", line 246, in find_all_tags
     get_tag_definitions(root_node, all_tags, search_string=name)
   File "/home/fshriver/test/opc_ua_client.py", line 110, in get_tag_definitions
     nodes = starting_node.get_children()
   File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/sync.py", line 94, in wrapper
     result = self.tloop.post(aio_func(*args, **kwargs))
   File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/sync.py", line 52, in post
     return futur.result()
   File "/usr/lib/python3.9/concurrent/futures/_base.py", line 440, in result
     return self.__get_result()
   File "/usr/lib/python3.9/concurrent/futures/_base.py", line 389, in __get_result
     raise self._exception
  File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/common/node.py", line 348, in get_children
     return await self.get_referenced_nodes(refs, ua.BrowseDirection.Forward, nodeclassmask)
   File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/common/node.py", line 421, in get_referenced_nodes
     references = await self.get_references(refs, direction, nodeclassmask, includesubtypes)
   File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/common/node.py", line 401, in get_references
     results = await self.server.browse(params)
   File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/client/ua_client.py", line 342, in browse
     data = await self.protocol.send_request(request)
   File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/client/ua_client.py", line 145, in send_request
     data = await asyncio.wait_for(self._send_request(request, timeout, message_type), timeout if timeout else None)
   File "/usr/lib/python3.9/asyncio/tasks.py", line 494, in wait_for
     raise exceptions.TimeoutError() from exc
 asyncio.exceptions.TimeoutError

Expected behavior
Like I said, there are only 520 tags in total, and they're all located under a single folder (the root node I pass in), so I don't expect there to be a huge issue even trawling through a bunch of paths, much less dealing with this number of tags. I'm not entirely sure what the issue is with threading here.

Version
Python-Version: 3.9.2
opcua-asyncio Version: 0.9.94

fshriver avatar Jul 16 '22 16:07 fshriver

get all tags with no children

what do you guys call tags? There is no notion of tags in opcua . You mean node?

atomic tags

that is also an interesting invention. what is an atomic tag?

I have to run the OPC-UA client globally and have different threads call functions on the client, but none of them should interfere as I only ever work with one thread.

Not sureI understand that stuff but the python client is threadsafe so you can call from many threads if you wan

    node_name = node.read_browse_name().to_string()```

It is much more efficient to use parent.get_children_descriptions() and you will get the browse name of all children at once

   data = await self.protocol.send_request(request)
   File "/home/fshriver/testenv/lib/python3.9/site-packages/asyncua/client/ua_client.py", line 145, in send_request
     data = await asyncio.wait_for(self._send_request(request, timeout, message_type), timeout if timeout else None)
   File "/usr/lib/python3.9/asyncio/tasks.py", line 494, in wait_for
     raise exceptions.TimeoutError() from exc
 asyncio.exceptions.TimeoutError
 ` ``

This is a timeout error waiting for the server. so it is you server not anwering in a reasonable time. It has probably limited ressources

oroulet avatar Jul 16 '22 16:07 oroulet