阿里云云助手后台任务被清杀?nohup 不够,要 setsid 脱离会话
在用阿里云云助手 RunCommand 于服务器上拉起 strace 采样、watch 循环和定时采样器时,调用一返回,后台任务就被静默清杀——产出是空文件,或只有第 1 针的半截文件,全程无任何报错。
在为客户提供 WordPress 中国站全托管 时踩到阿里云云助手的一个隐蔽行为——整站迁移、图片上云、每日备份与自动巡检的长期托管服务。
TL;DR
云助手调用结束会清理本次调用派生的后台进程,nohup 挡不住——它只忽略 SIGHUP 并重定向输出,进程仍留在原会话里,恰好在清理范围内。用 setsid 创建新会话才能逃出去:setsid nohup cmd < /dev/null &。回收产物前先验输出文件的行数与 mtime,别把空文件当成「命令没跑」。
问题现象:调用返回,后台任务静默消失
同一条 RunCommand 里 nohup cmd & 拉起的后台任务,三种形态死给你看:
| 任务 | 死法 |
|---|---|
| strace 采样 | 落盘文件根本未生成 |
| 定时采样器 v1 | 只出第 1 针,之后不再写入 |
| cpdavd watcher 首版 | 被清杀,进程消失 |
三种死法共享两个特征:调用本身返回成功(Success),服务器上无任何报错日志。搜「nohup 进程还是没了」「后台任务莫名消失」,答案大多指向 SIGHUP——但 nohup 明明已经加了。
根因:nohup 不换会话,清理按会话走
nohup 的语义只有两条:忽略 SIGHUP、把输出重定向到 nohup.out。它不做的事是换会话——进程还在云助手 agent 为本次调用创建的会话里。调用收尾时,agent 清理本次派生的进程,按会话归拢,nohup 任务一个都跑不掉。
setsid 的语义才是对症的:为新进程创建全新会话,使其脱离调用会话。脱离之后,收尾清理扫不到它——实测 strace、采样器、watcher 三类任务换成 setsid 后全部存活。
一条诚实的边界:agent 内部按什么粒度清(进程组还是会话)未做源码级查证,但「脱离原会话即存活」这个充分条件在三类任务上实证一致,够用了。
解决方案:setsid 三件套 + 产出验证
启动后台任务时,脱离会话、脱离终端、扔后台一步到位:
# 云助手脚本内拉起长时任务(采样器示例)
setsid nohup /usr/local/bin/sampler --interval 60 -o /tmp/samples.csv </dev/null >/tmp/sampler.log 2>&1 &
</dev/null 别省——后台任务的 stdin 若还挂在调用会话的终端语义上,存活了也可能停摆。
云助手是异步三段式(CreateCommand → InvokeCommand → DescribeInvocationResults),下发后约 10 秒再取结果;脚本里拉起后台任务后,脚本本身正常退出即可,不需要等任务。
回读产物前,先验任务是否真的活过:
# 行数应为预期针数;mtime 应持续推进
wc -l /tmp/samples.csv
stat -c %Y /tmp/samples.csv
空文件或只有第 1 针,说明任务没活下来——回去查 setsid 写法,而不是怀疑业务命令。这套「远程拉起、事后回读、先验产出」的流程,配合云助手留痕(ActionTrail)就是应急诊断的完整闭环。
这个教训反过来解释了服务器哨兵的架构口径:监控采集走机器上的常驻 agent 与本地 cron,备份脚本本地自跑、不依赖中心存活——长时任务的生命周期,不该绑在一次远程调用的收尾上。
注意事项
本文实证的形态是 setsid nohup cmd < /dev/null &,三件套各管一件事:setsid 换会话、nohup 兜 SIGHUP 与输出、stdin 重定向断开终端语义。产出验证放在回读之前——云助手调用的 Success 只代表脚本执行完毕,不代表后台任务还活着。另外 setsid 拉起的任务脱离了调用会话,也意味着后续调用无法直接管理它,需要留 PID 文件或按进程名定位。
常见问题
nohup 启动的进程为什么还是没了?
nohup 只做两件事:忽略 SIGHUP、重定向输出,进程仍留在原会话里。云助手调用结束时按会话清理本次派生的进程,nohup 任务恰好在清理范围内——实测 strace、采样器、watcher 三类任务全部被清,且调用本身返回成功、无任何报错。用 setsid 创建新会话才能逃出清理范围。
nohup 运行一段时间之后退出是怎么回事?
常见因有三类:启动方会话收尾清理、stdin 挂在已关闭的终端上、输出重定向目标消失。判别看时间点——本例采样器只出第 1 针就停,消失时刻与云助手调用返回严格同步,据此锁定是调用方清理而非任务自身崩溃。
云助手 RunCommand 里怎么让脚本常驻后台?
用 setsid、nohup、stdin 重定向三件套:setsid nohup cmd < /dev/null &。新会话不在调用收尾的清理范围内,任务跨调用存活。回收产物前先验产出文件行数与 mtime——空文件或半截文件说明任务没活下来,别把空结果当成命令没执行。