Python asyncua连接断开时CancelledError问题排查(Python3.7)
解决Python3.7 Linux下asyncua客户端断开连接时的CancelledError错误
问题根源
Python3.7的asyncio对任务取消的异常处理逻辑与Python3.10存在差异,asyncua的看门狗(watchdog)和会话续期(session renewal)后台任务在连接断开时被取消,但这些任务的代码未在3.7环境下正确捕获concurrent.futures._base.CancelledError,导致异常暴露并输出错误日志。
解决方案
1. 手动控制断开前的后台任务停止
在调用client.disconnect()前,先手动停止asyncua内部的看门狗和会话续期任务,避免任务被强制取消抛出异常:
import asyncio import concurrent.futures from asyncua import Client async def main(): client = Client(url="opc.tcp://your-server-url:port") try: await client.connect() # 执行读写操作 await client.write_node("ns=2;s=Tag1", 100) value = await client.read_node("ns=2;s=Tag2") print(f"读取到的值: {value}") finally: # 提前停止后台任务 try: # 停止会话续期任务 if hasattr(client, '_session_renewer') and client._session_renewer: client._session_renewer.stop() # 停止看门狗任务 if hasattr(client, '_watchdog') and client._watchdog: client._watchdog.stop() # 给后台任务一点时间退出 await asyncio.sleep(0.2) # 执行断开连接 await client.disconnect() except concurrent.futures.CancelledError: # 显式捕获Python3.7下的取消异常 pass except Exception as e: print(f"断开连接时出现非预期错误: {str(e)}") if __name__ == "__main__": asyncio.run(main())
2. 给asyncua的后台任务打猴子补丁
如果手动停止任务无效,可以通过猴子补丁修改asyncua内部任务的异常处理逻辑,让其在Python3.7下捕获CancelledError:
补丁看门狗任务
import asyncua.common.watchdog as watchdog_module import concurrent.futures original_watchdog_loop = watchdog_module.Watchdog._loop async def patched_watchdog_loop(self): try: await original_watchdog_loop(self) except concurrent.futures.CancelledError: # 捕获取消异常并标记任务停止 self._running = False # 替换原方法 watchdog_module.Watchdog._loop = patched_watchdog_loop
补丁会话续期任务
import asyncua.client.client as client_module import concurrent.futures original_renewer_run = client_module.SessionRenewer._run async def patched_renewer_run(self): try: await original_renewer_run(self) except concurrent.futures.CancelledError: # 捕获取消异常并停止任务 self._running = False # 替换原方法 client_module.SessionRenewer._run = patched_renewer_run
将上述补丁代码放在你初始化Client的代码之前即可生效。
3. 调整asyncua版本
部分asyncua版本对Python3.7的兼容性处理不足,可以尝试降级到0.9.13版本(该版本对Python3.7的任务取消异常处理更完善),注意:asyncua 1.0+版本已不再支持Python3.7,请勿升级到该系列。
内容的提问来源于stack exchange,提问作者kirba22
相关产品推荐
相关产品推荐

