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

解决pytest-xdist下libpython崩溃导致pytest挂起的问题

解决pytest-xdist下C代码调用abort()导致挂起的问题

针对你遇到的C代码调用abort()后,pytest-xdist多进程模式挂起的问题,给你几个可行的解决方案:

1. 在C绑定层捕获SIGABRT,转为Python异常

这是最彻底的解决方式,从根源避免进程崩溃导致的挂起。在你的Python C扩展代码里注册信号处理函数,把abort()触发的SIGABRT信号转换成Python异常抛出,让pytest能正常捕获并标记测试失败:

#include <signal.h>
#include <Python.h>
#include <setjmp.h>

static jmp_buf abort_jmp_buf;

static void handle_abort(int sig) {
    // 恢复默认信号处理,防止递归触发
    signal(sig, SIG_DFL);
    // 跳转到之前设置的点,抛出Python异常
    longjmp(abort_jmp_buf, 1);
}

// 封装调用C代码的函数
static PyObject* your_c_function(PyObject* self, PyObject* args) {
    // 设置跳转点
    if (setjmp(abort_jmp_buf) == 0) {
        // 注册信号处理
        signal(SIGABRT, handle_abort);
        // 调用你的C代码,可能触发abort()
        your_actual_c_code();
        Py_RETURN_NONE;
    } else {
        // 抛出Python异常
        PyErr_SetString(PyExc_RuntimeError, "C code triggered abort()");
        return NULL;
    }
}

PyMODINIT_FUNC PyInit_your_module(void) {
    static PyMethodDef methods[] = {
        {"your_c_function", your_c_function, METH_VARARGS, "Call C code"},
        {NULL, NULL, 0, NULL}
    };
    static struct PyModuleDef module = {
        PyModuleDef_HEAD_INIT,
        "your_module",
        NULL,
        -1,
        methods
    };
    return PyModule_Create(&module);
}

这样修改后,当C代码调用abort()时,会触发信号处理函数,转而抛出Python异常,不管单进程还是多进程模式,pytest都能正常捕获并标记测试失败,不会挂起。

2. 自定义pytest钩子监控worker进程状态

如果无法修改C代码,可以通过pytest的钩子函数监控xdist worker的退出状态,当检测到异常退出时强制终止主进程:

在项目根目录创建conftest.py,添加以下代码:

import pytest
from pytest_xdist.remote import RemoteTestSession

def pytest_testnodedown(node, error):
    # 检查worker节点是否异常退出
    if isinstance(node, RemoteTestSession):
        # 134是abort()对应的退出码,也可以扩展到其他崩溃码
        if node.exitstatus == 134 or node.exitstatus < 0:
            pytest.exit(f"Worker {node.gateway.id} crashed with exit code {node.exitstatus}", returncode=1)

这个钩子会在worker节点下线时检查其退出码,如果是abort()对应的134或者负数值(表示被信号终止),就让pytest主进程直接退出并返回失败状态。

3. 用pytest-timeout强制终止超时测试

如果上面的方法都不生效,可以给测试添加超时限制,用pytest-timeout插件强制终止挂起的测试:

  1. 安装插件:
pip install pytest-timeout
  1. 运行测试时添加超时参数:
pytest -n auto --timeout=5

或者在测试函数上直接加装饰器:

import pytest

@pytest.mark.timeout(5)
def test_c_abort_scenario():
    # 调用你的C绑定代码
    your_module.your_c_function()

这样即使测试因为abort()挂起,超时后会被自动终止,主进程不会一直无响应。

4. 开启xdist严格模式

结合你试过的--max-worker-restart 0,再加--xdist-strict参数,让主进程在worker崩溃时直接终止测试会话:

pytest -n auto --max-worker-restart 0 --xdist-strict

这个选项会禁用worker重试,一旦有worker崩溃,主进程就会立即退出并标记测试失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:00:41