🧟‍♂️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 脚本嗝屁了,就立刻:

  1. 自动重启该脚本;
  2. 查看 Redis 中失败队列;
  3. 如果失败任务数大于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,而是那些莫名其妙就挂了、还得手动救的“幽灵进程”。

希望这篇文章能帮你少受点苦、多睡点觉~

如果你觉得有用,点个赞 👍 收藏 ⭐️,让我知道你也在和我一样和进程死磕的路上!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐