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

BadSessionIdInvalid after 30s

Open jmtatsch opened this issue 2 years ago • 5 comments

Describe the bug
Connect to an S7 with opcua-client, client attempts to negotiate a timeout of an hour but gets only 30s. asyncua.client.client - WARNING - Requested session timeout to be 3600000ms, got 30000ms instead') After 30s client gets BadSessionIdInvalid and crashes.

asyncua.client.ua_client.UASocketProtocol - WARNING - ServiceFault (BadSessionIdInvalid, diagnostics: DiagnosticInfo(SymbolicId=None, NamespaceURI=None, Locale=None, LocalizedText=None, AdditionalInfo=None, InnerStatusCode=None, InnerDiagnosticInfo=None)) from server received  in response to ReadRequest')
uawidgets.utils - ERROR - "The session id is not valid."(BadSessionIdInvalid)')
Traceback (most recent call last):
  File "/home/jtatsch/.local/lib/python3.8/site-packages/opcua_widgets-0.6.1-py3.8.egg/uawidgets/utils.py", line 21, in wrapper
    result = func(self, *args)
  File "/home/jtatsch/.local/lib/python3.8/site-packages/opcua_client-0.8.4-py3.8.egg/uaclient/mainwindow.py", line 437, in _update_actions_state
    if node.read_node_class() == ua.NodeClass.Method:
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/sync.py", line 94, in wrapper
    result = self.tloop.post(aio_func(*args, **kwargs))
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/sync.py", line 52, in post
    return futur.result()
  File "/usr/lib/python3.8/concurrent/futures/_base.py", line 444, in result
    return self.__get_result()
  File "/usr/lib/python3.8/concurrent/futures/_base.py", line 389, in __get_result
    raise self._exception
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/common/node.py", line 144, in read_node_class
    result = await self.read_attribute(ua.AttributeIds.NodeClass)
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/common/node.py", line 302, in read_attribute
    result = await self.server.read(params)
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/client/ua_client.py", line 365, in read
    data = await self.protocol.send_request(request)
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/client/ua_client.py", line 154, in send_request
    self.check_answer(data, f" in response to {request.__class__.__name__}")
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/client/ua_client.py", line 163, in check_answer
    hdr.ServiceResult.check()
  File "/home/jtatsch/.local/lib/python3.8/site-packages/asyncua-0.9.94-py3.8.egg/asyncua/ua/uatypes.py", line 328, in check
    raise UaStatusCodeError(self.value)
asyncua.ua.uaerrors._auto.BadSessionIdInvalid: "The session id is not valid."(BadSessionIdInvalid)

Expected behavior
I would expect some kind of keep alive mechanism to keep the session alive so it does not become invalid and crash.

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

jmtatsch avatar Jul 28 '22 17:07 jmtatsch

Looked into the code and found that there is a keep alive implemented, just the calculation of the duration is wrong.

Clients should request a new SecurityToken after 75 % of its lifetime has elapsed duration = self.secure_channel_timeout * 0.75 / 1000

instead of the self.secure_channel_timeout it should use the permitted session timeout received from the server in self.session_timeout.

jmtatsch avatar Jul 28 '22 18:07 jmtatsch

No this is no bug, this is how opc ua works. The session timeout is reset when you send a request, so just have one subscription is enough, to prevent a session timeout. No seecure channel has nothing todo with a session and changing the securechannel renewal is not good because conforming servers can raise errors if you do it to early (earliest 0.25 of the time is allowed!). The whole reconnect and session reconnect is currently missing, so there is no easy fix atm.

schroeder- avatar Jul 29 '22 05:07 schroeder-

Guess I abused the secure channel timeout watchdog then. However it mitigated my issue effectively 😆 However, if the session has timed out the secure channel is dead as well, right?

Would you be fine with a second watchdog mechanism to exclusively manage the session timeout? Is there something like a Nop that we can send to not abuse the secure channel stuff?

jmtatsch avatar Jul 29 '22 06:07 jmtatsch

A secure channel can outlive a a session. Also a secure channel can have multiple sessions (our client doesn't support that). Currently we are missing reconnecting strategies so there it doesn't work.

The easiest thing currently is to subscribe to a random variable or read a variable with a timer.

schroeder- avatar Jul 29 '22 06:07 schroeder-

To keep alive the connection I subcribe for the time in the server.

f3lixTRS avatar Jul 29 '22 11:07 f3lixTRS