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

GitLab CI任务状态监听:手动取消/超时后清理脚本实现疑问

关于GitLab CI任务清理的两个疑问解答

问题1:使用os.waitpid()无法获取GitLab Runner的进程ID?

GitLab Runner执行Job时,会创建独立的子进程运行你的脚本,你在脚本中拿到的PID通常是当前脚本进程或Runner为Job创建的Shell进程ID,而非Runner主进程ID。

  • 若要监控Job自身启动的子进程(如后台服务、临时进程),应跟踪你自己启动的进程PID(比如写入PID文件),而非尝试获取Runner主进程ID。
  • os.waitpid()仅能处理当前进程的子进程,Runner主进程不属于你的Job进程的子进程链,且普通用户权限无法操作Runner主进程,因此用它无法获取Runner的进程ID。
  • 若需查找Runner相关进程,可通过pstree -p $$查看当前Shell的父进程链,但这种方法依赖环境,可靠性不高,因为Runner的进程结构可能因配置不同变化。

问题2:CI_JOB_STATUS似乎仅能在脚本执行完成后使用?

确实如此,CI_JOB_STATUS是GitLab在整个Job执行完成后才设置的环境变量,仅能在after_script阶段或Job收尾环节拿到正确值,无法用于实时监听任务取消/超时状态。

要在任务被手动取消或超时的实时场景触发清理,需换用以下思路:

  • 监听系统信号:GitLab Runner取消Job时会向Job进程发送SIGTERM信号(超时场景可能先发送SIGTERM,后续再发送SIGKILL)。你可以在Python脚本中注册信号处理函数,收到信号时立即执行清理逻辑。
  • 示例代码:
import signal
import os
import sys

def cleanup(signum, frame):
    # 自定义清理逻辑:终止子进程、删除临时文件等
    print("收到取消信号,开始执行清理...")
    # 读取之前保存的子进程PID并终止
    if os.path.exists("task_pid"):
        with open("task_pid", "r") as f:
            child_pid = int(f.read())
        try:
            os.kill(child_pid, signal.SIGTERM)
            os.waitpid(child_pid, 0)
        except OSError:
            pass
    sys.exit(0)

# 注册信号监听
signal.signal(signal.SIGTERM, cleanup)
signal.signal(signal.SIGINT, cleanup)

# 主任务逻辑
print("启动主任务...")
# 启动后台子进程并保存PID
child_pid = os.fork()
if child_pid == 0:
    os.execvp("sleep", ["sleep", "3600"])
else:
    with open("task_pid", "w") as f:
        f.write(str(child_pid))
    os.waitpid(child_pid, 0)
  • after_script适合做Job结束后的收尾清理,但无法实时响应取消/超时事件,实时场景仍需依赖信号监听。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 03:43:18