linux没有原生“自愈脚本”概念,真正的自愈需结合systemd的restart机制与脚本内显式健康检查、清理和恢复逻辑,避免依赖rc.local或crontab @reboot等单次启动方式。

直接说结论:Linux没有“自愈脚本”这个原生概念,所谓“自愈”,本质是让脚本在崩溃后自动重启、异常时触发修复逻辑,这必须靠 systemd 的 Restart 机制 + 显式错误检测逻辑来实现,不能靠 rc.local 或 crontab @reboot 单次启动糊弄过去。
systemd 服务中设置 Restart=always 不等于真能自愈
很多人写完 Restart=always 就以为万事大吉,结果脚本崩了也不拉起。原因很实在:
-
Restart=always只对进程退出生效,如果脚本卡死(比如死循环、阻塞在 read()、hang 在网络请求上),systemd 根本不认为它“退出”,就不会重启; - 默认
RestartSec=100ms,太短容易触发限频(StartLimitIntervalSec和StartLimitBurst限制),连续崩 5 次后 systemd 会直接放弃; - 没配
TimeoutSec的话,systemd 等不到你的脚本“正常退出”,可能强行 kill,导致状态混乱。
真正可用的配置得像这样:
[Service] ExecStart=/opt/myselfheal.sh Restart=always RestartSec=5 StartLimitIntervalSec=60 StartLimitBurst=3 TimeoutSec=30
意思是:每次崩了等 5 秒再拉起,1 分钟内最多拉 3 次,单次运行超 30 秒就强制终止。
脚本内部必须自己做健康检查和恢复动作
systemd 只管进程存不存在,不管业务逻辑是否正常。比如一个监控磁盘空间的脚本,光重启没用——如果磁盘满了,重启 10 次还是满的。所以脚本里得有明确的“自愈”逻辑:
- 启动前检查依赖:用
pidof或ss -tlnp | grep :8080确认端口没被占; - 运行中定期探测:比如每 30 秒
curl -f http://localhost:8080/health || systemctl restart myscript.service; - 失败后清理:删临时文件、重置锁文件、清空
/tmp/.lock; - 避免无限递归:不要在脚本里直接调
systemctl restart,改用外部 watchdog 或 systemd 的ExecReload。
别把 /etc/rc.local 当自愈入口
rc.local 是一次性执行环境,连 & 后台运行都容易被 init 进程回收,更别说崩溃后重启。常见翻车点:
- 脚本里用了
source ~/.bashrc—— rc.local 用的是/bin/sh,不是 bash,语法直接报错; - 写了
python3 /path/to/app.py &,但没加nohup或setsid,父进程一退子进程跟着挂; - 路径写相对路径(如
./check.sh),rc.local 执行时 pwd 是 /,脚本根本找不到。
真要用 rc.local,只适合发个信号或触发一次初始化,比如:systemctl start myselfheal.service —— 把“自愈”这件事交给 systemd,别自己硬扛。
crontab @reboot 无法提供进程守护能力
@reboot 只是开机跑一次,跟“自愈”完全不沾边。更麻烦的是:
- 它运行在用户 crond 上下文,
$PATH很窄,which python3可能返回空; - 没配
cd /path/to/script就直接python3 main.py,大概率报ModuleNotFoundError; - 日志全丢进 mail 或默默消失,出问题根本不知道崩在哪一行。
除非你写的脚本本身就是“执行完就退出”的一次性任务(比如清理旧日志、校验配置文件),否则别碰 @reboot 做守护。
最易被忽略的一点:自愈的前提是“可诊断”。所有关键判断点(磁盘满、端口占用、HTTP 返回非 200)都得打日志,且日志路径不能写 /var/log/myapp/ 这种可能还没 mount 好的目录——优先用 /tmp/ 或 systemd 的 journalctl -u myscript.service。











