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
相关产品推荐
相关产品推荐

