PHP 脚本进程总是“猝死”?一招教你自动拉他回魂 + Redis 任务失败自救!
·
🧟♂️PHP 脚本进程总是“猝死”?一招教你自动拉他回魂 + Redis 任务失败自救!
关键词:PHP 队列挂掉、自动重启、Redis失败任务恢复、crontab守护脚本、linux进程检测

🧑💻 前情提要:有个队列,它总是暴毙
作为一名努力搬砖的个人开发者,我负责的一个项目中有个 PDF 队列生成脚本,看似跑得风生水起,其实命悬一线。这个脚本运行方式是这样的:
cd /www/my-site-root
nohup /www/server/php/73/bin/php -c /www/server/php/73/etc/php-cli.ini public/index.php index/pdf_redis_queue/run &> pdf_redis_queue/pdf_redis_queue.out &
后台乖乖生成 PDF,一切看似太平。
但现实很骨感——服务器重启?脚本挂了;
内存一抖?脚本挂了;
代码一更新?你猜对了,还是挂了。
于是,我不得不每天像个苦命运维,反复敲命令查看:
ps -ef | grep pdf_redis_queue
看到没跑就重启,完事还得翻 Redis 失败任务列表挨个 RPOPLPUSH 手动补救。属实 人在队列在,脚本没了我就上!
😤 不,我要自动化!
我要让这个破脚本自己活着,自己爬起来,顺带把失败任务也拯救一下。于是,我写了一个自动守护 + 自救机制的脚本 —— 让它每分钟巡逻一次,一旦发现 PHP 脚本嗝屁了,就立刻:
- 自动重启该脚本;
- 查看 Redis 中失败队列;
- 如果失败任务数大于1,就自动执行
RPOPLPUSH,一口气把这些失败任务喂回去再来一遍!
🧠 解决方案:自动守护脚本 monitor_pdf_queue.sh
把以下内容保存为 monitor_pdf_queue.sh,记得替换目录路径:
#!/bin/bash
# -------------------配置区域-------------------
WEB_ROOT="/your/website/root" # ⚠️ 修改为你的网站根目录
PHP_BIN="/www/server/php/73/bin/php"
PHP_INI="/www/server/php/73/etc/php-cli.ini"
SCRIPT="public/index.php index/pdf_redis_queue/run"
LOG_DIR="$WEB_ROOT/pdf_redis_queue"
LOG_FILE="$LOG_DIR/pdf_redis_queue.out"
MONITOR_LOG="$LOG_DIR/monitor.log"
# Redis 相关配置
REDIS_CMD="redis-cli -a 'you_redis_password'"
QUEUE_BAK="queue_gen_pdf_bak"
QUEUE_MAIN="queue_gen_pdf"
# -------------------执行区域-------------------
START_CMD="nohup $PHP_BIN -c $PHP_INI $WEB_ROOT/$SCRIPT &> $LOG_FILE &"
PROCESS_KEY="index/pdf_redis_queue/run"
# 记录时间
timestamp=$(date '+%F %T')
# 检查进程是否在跑
is_running=$(ps -ef | grep "$PROCESS_KEY" | grep -v grep)
if [ -z "$is_running" ]; then
echo "[$timestamp] 进程挂了,马上 CPR 中..." >> "$MONITOR_LOG"
cd "$WEB_ROOT" && eval "$START_CMD"
echo "[$timestamp] 脚本已复活!" >> "$MONITOR_LOG"
# 检查 Redis 失败任务数
fail_count=$($REDIS_CMD LLEN "$QUEUE_BAK")
echo "[$timestamp] 当前失败任务数:$fail_count" >> "$MONITOR_LOG"
# 如果失败任务 > 1,恢复 (N - 1) 次
if [ "$fail_count" -gt 1 ]; then
retries=$((fail_count - 1))
echo "[$timestamp] 准备恢复 $retries 个任务..." >> "$MONITOR_LOG"
for i in $(seq 1 $retries); do
$REDIS_CMD RPOPLPUSH "$QUEUE_BAK" "$QUEUE_MAIN"
echo "[$timestamp] 已恢复第 $i 个失败任务" >> "$MONITOR_LOG"
done
fi
else
echo "[$timestamp] 进程健康,无需操作。" >> "$MONITOR_LOG"
fi
🛠️ 安装步骤(别怕,很简单)
第一步:把脚本扔到你项目目录
建议放在你的 /your/website/root/pdf_redis_queue/ 目录下。
chmod +x monitor_pdf_queue.sh
第二步:加个 crontab 任务,让它每分钟巡逻一次
crontab -e
加入这一行:
* * * * * /your/website/root/pdf_redis_queue/monitor_pdf_queue.sh
保存退出,完事!
🔍 效果展示
日志在 monitor.log 文件中,会长这样:
[2025-07-16 14:01:00] 进程挂了,马上 CPR 中...
[2025-07-16 14:01:00] 脚本已复活!
[2025-07-16 14:01:00] 当前失败任务数:8
[2025-07-16 14:01:00] 准备恢复 7 个任务...
[2025-07-16 14:01:00] 已恢复第 1 个失败任务
...
一条龙服务,从抢救 PHP 到回收 Redis,根本不用你操心。
🎯 总结一下:
| 功能 | 有吗? |
|---|---|
| 进程挂了自动拉起来 | ✅ |
| 重启脚本前定位异常 | ✅ |
| Redis 失败任务自动恢复 | ✅ |
| 脚本日志记录 | ✅ |
| 开发者安心睡觉 | ✅ ✅ ✅ |
🧩 后续可选进阶(我正在考虑):
- 用
systemd写成服务,支持开机自启 + 自动重启 + 崩溃重试; - Telegram/企业微信报警通知;
- 失败任务量暴涨报警机制(比如一次100个失败任务就报警);
🐾写在最后
这个小脚本虽然简单,却大大提高了我的幸福感。要知道,开发者的最大敌人从来不是 Bug,而是那些莫名其妙就挂了、还得手动救的“幽灵进程”。
希望这篇文章能帮你少受点苦、多睡点觉~
如果你觉得有用,点个赞 👍 收藏 ⭐️,让我知道你也在和我一样和进程死磕的路上!
更多推荐
所有评论(0)