升级Python至3.10.7后PyTest执行完成无法终止问题求助
排查思路与解决办法
1. 检查异步资源未清理
- 确认测试中所有异步客户端(比如
TestClient或自定义aiohttp客户端)都正确调用close():Python 3.10+对异步上下文的处理更严格,未关闭的客户端会残留事件循环资源。 - 排查测试中是否有未await的异步任务、FastAPI
BackgroundTasks:这些任务可能在测试结束后仍后台运行,阻塞事件循环。可在测试末尾强制等待后台任务完成:from fastapi import BackgroundTasks def test_demo(): tasks = BackgroundTasks() # 测试逻辑 # 强制执行所有后台任务 for task in tasks.tasks: await task() - 检查自定义异步管理器(如数据库连接池、Redis客户端),测试后需关闭连接池,避免占用事件循环。
2. 验证Pytest插件兼容性
- 升级测试相关插件到适配Python 3.10的版本:比如
pytest-asyncio需确保版本≥0.19.0,旧版本插件可能在新Python版本下出现资源泄漏。 - 逐个禁用非必要插件排查:用
pytest -p no:插件名命令,逐步定位是否是某个插件导致的无法终止问题。
3. 事件循环相关调试
- 显式指定事件循环策略:在
conftest.py中添加固定的事件循环管理逻辑,避免系统默认策略的差异问题:import asyncio import pytest @pytest.fixture(scope="session") def event_loop(): policy = asyncio.get_event_loop_policy() loop = policy.new_event_loop() yield loop loop.close() - 测试结束后检查未完成任务:在teardown阶段添加代码,打印残留任务定位问题:
import asyncio def teardown_function(): loop = asyncio.get_event_loop() pending = asyncio.all_tasks(loop) if pending: print(f"未完成任务列表: {pending}") # 强制取消并清理所有任务 for task in pending: task.cancel() loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
4. 升级核心依赖版本
- 升级FastAPI和Starlette到最新稳定版:Python 3.10对异步语法和事件循环的处理有调整,旧版本框架可能存在兼容性问题,导致资源无法释放。
- 同步升级其他异步依赖:比如
uvicorn、aiohttp、异步版sqlalchemy等,确保所有依赖都适配Python 3.10。
5. CI环境特殊处理
- Docker容器中检查进程残留:测试结束后用
ps aux查看是否有Python进程未退出,可能是后台任务脱离了测试进程。 - 临时添加强制终止命令:在CI脚本测试步骤后执行
pkill -f python作为临时 workaround,找到根本原因后再移除。
内容的提问来源于stack exchange,提问作者silenum
相关产品推荐
相关产品推荐

