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

FastAPI使用nest_asyncio.apply()时GitHub Action pytest无法自动终止

问题原因

nest_asyncio.apply()会修改Python asyncio原生事件循环的实现逻辑,解除事件循环不可嵌套运行的限制,同时会改变事件循环的默认退出判定规则。

  • 本地运行pytest时,交互终端环境会在测试进程退出前隐式回收残留的事件循环资源,因此进程可以正常退出。
  • GitHub Actions是无交互CI环境,被nest_asyncio修补过的事件循环会残留对标准IO等文件描述符的事件监听,pytest执行完所有用例后会持续等待事件循环任务完全清空,进程不会主动返回退出码,表现为步骤持续运行无响应。
  • 移除nest_asyncio.apply()后事件循环恢复原生逻辑,pytest可正常完成事件循环回收,因此流程能正常结束。
修复方案

可根据业务场景选择以下方案,优先推荐前两种:

  • 方案1:添加pytest会话级清理逻辑
    在项目根目录新建conftest.py,添加如下代码,所有测试用例执行完成后手动取消残留任务、关闭事件循环,彻底解决阻塞问题:

    import asyncio
    import pytest
    
    @pytest.fixture(scope="session", autouse=True)
    def cleanup_event_loop():
        yield
        loop = asyncio.get_event_loop()
        # 取消所有未执行完成的残留任务
        pending_tasks = [t for t in asyncio.all_tasks(loop) if not t.done()]
        for task in pending_tasks:
            task.cancel()
        loop.run_until_complete(asyncio.gather(*pending_tasks, return_exceptions=True))
        # 停止并关闭事件循环
        loop.stop()
        loop.close()
    

    注意原test_main.py缺少TestClient的导入,需要补充,否则运行时会抛出NameError:

    # test_main.py 修正后
    from fastapi.testclient import TestClient
    from .main import app
    
    client = TestClient(app)
    
    
    def test_hello():
        res = client.get('/hello')
        assert res.status_code == 200
    
  • 方案2:调整nest_asyncio补丁的生效范围
    不要在main.py模块顶层直接调用nest_asyncio.apply(),将这行代码移动到实际需要嵌套事件循环能力的业务函数内部,仅在业务逻辑执行时打补丁,避免补丁影响测试框架的事件循环逻辑:

    # main.py 调整示例
    from fastapi import FastAPI
    import nest_asyncio
    
    app = FastAPI()
    
    def business_func_need_nest_loop():
        # 仅在实际需要时才应用补丁
        nest_asyncio.apply()
        # 原有调用asyncio.get_event_loop()的业务逻辑
        ...
    
    @app.get('/hello')
    def hello():
        return {'msg': 'hello'}
    
  • 方案3:为pytest命令增加超时限制(临时方案)
    若暂时不想修改业务代码,可直接修改GitHub Actions工作流中的pytest执行命令,增加超时阈值强制结束进程,超时时间设置为大于所有测试用例的预估执行时长即可:

    # python-app.yml 中测试步骤修改示例
    - name: Test with pytest
      run: |
        timeout 60 pytest
    

    该方案无法区分正常残留和测试用例死锁,仅适合临时快速修复场景。


内容的提问来源于stack exchange,提问作者Angie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 11:39:20