
本文详解为何 Cron 脚本中 pm2 list 无法正确获取运行中的 PM2 进程,核心原因是环境变量与用户上下文差异;通过指定绝对路径、切换用户及设置环境变量可彻底解决误报问题。
本文详解为何 cron 脚本中 `pm2 list` 无法正确获取运行中的 pm2 进程,核心原因是环境变量与用户上下文差异;通过指定绝对路径、切换用户及设置环境变量可彻底解决误报问题。
在使用 PM2 管理 PHP 或 Node.js 后台服务时,常需编写健康检查脚本(如定期扫描 pm2 list 输出),并在发现关键服务异常退出时自动发送告警邮件。你已实现基础逻辑:通过 array_diff() 比对预设服务列表 $required 与当前运行列表 $running,一旦发现差集 $errored 就调用 mail() 发送通知——本地手动执行完全正常。
但当该脚本交由系统 Cron 执行时,却频繁误报“所有服务已停止”。根本原因在于:Cron 默认以 root 用户(或配置用户)在极简 shell 环境中运行,既无你的用户(如 ubuntu)的 PATH,也未加载 PM2 的全局安装路径(如 /home/ubuntu/.nvm/versions/node/v18.18.2/bin/pm2),更未继承 PM2 的进程命名空间(PM2 以用户级守护模式运行,root 用户默认看不到 ubuntu 启动的 PM2 实例)。
✅ 正确解决方案需三步协同:
-
使用绝对路径调用
pm2
不要依赖shell_exec('pm2 list --no-color'),而应明确指定完整路径。可通过which pm2查得(例如/usr/local/bin/pm2或~ubuntu/.nvm/versions/node/v18.18.2/bin/pm2),并在脚本中硬编码:$pm2_bin = '/home/ubuntu/.nvm/versions/node/v18.18.2/bin/pm2'; $output = shell_exec("$pm2_bin list --no-color 2>&1"); -
确保以正确用户身份执行 Cron
编辑ubuntu用户的 crontab(而非 root 的):sudo -u ubuntu crontab -e # 添加如下行(每5分钟检查一次) */5 * * * * /usr/bin/php /home/ubuntu/scripts/pm2-healthcheck.php >> /home/ubuntu/logs/pm2-check.log 2>&1
-
显式加载必要环境变量(可选但推荐)
若 PM2 依赖 nvm 或特定 Node 版本,在脚本开头添加:putenv('PATH=/home/ubuntu/.nvm/versions/node/v18.18.2/bin:/usr/local/bin:/usr/bin:/bin'); putenv('HOME=/home/ubuntu');
⚠️ 注意事项:
- 避免在 root crontab 中用
sudo -u ubuntu调用——可能因密码策略或 tty 限制失败; -
pm2 list输出含 ANSI 色彩字符,务必加--no-color参数,否则正则解析易出错; - 建议将
$running解析逻辑增强健壮性,例如用preg_match_all('/^(?<name>\S+)\s+\d+\s+(online|stopped)/m', $output, $matches)</name>提取服务名与状态; - 生产环境建议改用
pm2 show <app></app>或pm2 ping接口做精准状态校验,而非依赖文本解析。
通过以上调整,你的健康检查脚本即可在 Cron 中稳定、准确地识别真实服务故障,并可靠触发邮件告警。










