Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscription tasks not closed properly on OPCUA server shutdown #1652

Open
MaciejPMarciniak opened this issue Jun 3, 2024 · 2 comments
Open

Comments

@MaciejPMarciniak
Copy link

Describe the bug

When the server is closed / restarted by remote operators, the BadShutdown status is sent to the StatusChangeNotification. The tasks running in the threadloop are not closed, which causes the running program to hang. Some of the tasks are cancelled, which results in asyncio's CancelledError, which is not handled.

To Reproduce

async def start(self, nodes):
    ...
    return await self.api.subscribe(self, nodes, self.time_to_live)
async def subscribe(self, handler, node_names, lifetime):
        try:
            self.thread.post(self.do_subscribe(handler, node_names, lifetime))
        except TimeoutError as e:
            self.logger.error(
                f"TimeoutError: no response from server after {self.post_timeout} seconds"
            )
            self.stop()  # Close the connection to the server, never reached
          ...

async def do_subscribe(self, handler, node_names, lifetime):
        client = await self.client()  # method for connecting to the server
        nodes = [client.get_node(f"ns={self.namespace_index};s={node_name}") for node_name in node_names]
        subscription = await client.create_subscription(500, handler)
        await subscription.subscribe_data_change(nodes)
        await asyncio.sleep(lifetime)
        await subscription.delete()
        await asyncio.sleep(1)

This is the setup. The error occurs when the server is closed remotely.

Expected behavior

All tasks are either executed or cancelled gracefully, such that the program does not hang.

Screenshots

[OPCUA] [asyncua.client.client] [ERROR] Error in watchdog loop
Traceback (most recent call last):
File "/home/_/.pyenv/versions/3.12.2/lib/python3.12/asyncio/[tasks.py](http://tasks.py/)", line 520, in wait_for
return await fut
^^^^^^^^^
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/client/[client.py](http://client.py/)", line 552, in _monitor_serverloop
\ = await self.nodes.server_state.read_value()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/common/[node.py](http://node.py/)", line 207, in read_value
result = await self.read_data_value()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/common/[node.py](http://node.py/)", line 220, in read_data_value
return await self.read_attribute(ua.AttributeIds.Value, None, raise_on_bad_status)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/common/[node.py](http://node.py/)", line 342, in read_attribute
result = await self.session.read(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/client/ua_client.py", line 404, in read
data = await self.protocol.send_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/client/ua_[client.py](http://client.py/)", line 167, in send_request
data = await asyncio.wait_for(self._send_request(request, timeout, message_type), timeout if timeout else None)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/.pyenv/versions/3.12.2/lib/python3.12/asyncio/[tasks.py](http://tasks.py/)", line 519, in wait_for
async with timeouts.timeout(timeout):
File "/home/_/.pyenv/versions/3.12.2/lib/python3.12/asyncio/[timeouts.py](http://timeouts.py/)", line 115, in aexit
raise TimeoutError from exc_val
TimeoutError

[OPCUA] [asyncua.common.subscription] [ERROR] Exception calling status change handler
Traceback (most recent call last):
File "/home/_/.pyenv/versions/3.12.2/lib/python3.12/asyncio/[tasks.py](http://tasks.py/)", line 520, in wait_for
return await fut
^^^^^^^^^
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/client/[client.py](http://client.py/)", line 552, in _monitor_serverloop
\ = await self.nodes.server_state.read_value()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/common/[node.py](http://node.py/)", line 207, in read_value
result = await self.read_data_value()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/common/[node.py](http://node.py/)", line 220, in read_data_value
return await self.read_attribute(ua.AttributeIds.Value, None, raise_on_bad_status)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/common/[node.py](http://node.py/)", line 342, in read_attribute
result = await self.session.read(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/client/ua_client.py", line 404, in read
data = await self.protocol.send_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/work/EEP_DataExtractor_pipeline/.venv/lib/python3.12/site-packages/asyncua/client/ua_[client.py](http://client.py/)", line 167, in send_request
data = await asyncio.wait_for(self._send_request(request, timeout, message_type), timeout if timeout else None)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/_/.pyenv/versions/3.12.2/lib/python3.12/asyncio/[tasks.py](http://tasks.py/)", line 519, in wait_for
async with timeouts.timeout(timeout):
File "/home/_/.pyenv/versions/3.12.2/lib/python3.12/asyncio/[timeouts.py](http://timeouts.py/)", line 115, in aexit
raise TimeoutError from exc_val
TimeoutError

If applicable, add screenshots to help explain your problem.

Version

Python-Version: 3.12

opcua-asyncio Version (e.g. master branch, 0.9): 1.1.0

@oroulet
Copy link
Member

oroulet commented Jun 8, 2024

what task is still running?

@MaciejPMarciniak
Copy link
Author

renew_channel_loop and monitor_server_loop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants