You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 15:55:21