Workerman需自建监控脚本而非依赖Supervisor/systemd,因其仅监控主进程存活而无法感知子进程崩溃、EventLoop卡死等内部异常;应通过status命令解析或HTTP接口检查worker_status和活跃进程数,并结合业务探活确保真实可用性。

Workerman 进程挂了不会自动拉起,靠 php start.php start -d 启动后就彻底“放养”了——必须自己加监控脚本,否则线上服务一崩就是几十分钟没人发现。
为什么不能只靠 Supervisor 或 systemd?
Supervisor 和 systemd 确实能拉起进程,但 Workerman 的 Worker::runAll() 是阻塞式长循环,子进程(比如业务逻辑里 exec 或 shell_exec)崩溃、内存溢出、未捕获异常,都可能让整个 Worker 实例静默退出,而主进程仍存活——此时 Supervisor 认为“服务还在”,根本不会触发重启。
真正要监控的是:Worker 子进程是否真实在处理连接、status 接口是否返回正常、端口是否可连通。
- Supervisor 只管主 PHP 进程 PID 是否存在,不感知内部状态
- systemd 默认也只 watch 主进程,需额外配置
RestartSec=1+Restart=on-failure,但仍无法覆盖子进程卡死场景 - Workerman 自带的
status命令(php start.php status)输出是文本,得自己 parse,且默认不开放 HTTP status 接口,得手动开
用 shell 脚本轮询 status 输出最轻量可靠
不用引入 Python/Node.js,纯 bash 就够。关键是判断逻辑不能只看“进程是否存在”,而要看 php start.php status 输出里有没有 worker_status: 1(表示有活跃 worker)、有没有 processes: [0-9]+ 且数值 > 0。
示例检查逻辑:
#!/bin/bash
cd /path/to/workerman/app
if ! php start.php status 2>/dev/null | grep -q "worker_status: 1" || \
! php start.php status 2>/dev/null | grep -o "processes: [0-9]*" | grep -q "processes: [1-9]"; then
echo "$(date) - Workerman not healthy, restarting..." >> /var/log/workerman/watch.log
php start.php restart >/dev/null 2>&1
fi- 必须用
restart而不是stop && start,避免端口 TIME_WAIT 冲突 - 加
2>/dev/null防止 status 命令报错(如未启动时)干扰判断 - 不要用
ps aux | grep start.php,容易误杀其他 PHP 脚本 - 建议每 5 秒执行一次:
*/1 * * * * sleep 5; /path/to/watch.sh放 cron,或用while true; do ./watch.sh; sleep 5; done后台跑
更稳的做法:暴露 HTTP status 接口 + curl 检查
在 Workerman 启动脚本里加一段,让其监听一个内网端口(比如 127.0.0.1:12345),响应简单 JSON:
$http = new Worker('http://127.0.0.1:12345');
$http->count = 1;
$http->onMessage = function($connection, $data) {
$connection->send(json_encode(['status' => 'ok', 'workers' => Worker::$pidArray ? count(Worker::$pidArray) : 0]));
};然后监控脚本改用:
if ! curl -s --connect-timeout 2 http://127.0.0.1:12345 | jq -e '.status == "ok" and .workers > 0' >/dev/null; then
php start.php restart
fi- 比解析文本更健壮,避免正则误匹配
-
--connect-timeout 2防止卡死,超时即判失败 - 必须绑定
127.0.0.1,禁止外网访问 - 注意:Workerman 默认不装
jq,线上机器得提前apt install jq或改用grep -q '"status":"ok"' | grep -q '"workers":[1-9]'
真正的难点不在“怎么重启”,而在“怎么定义‘挂了’”。端口通、进程在、status 命令返回成功,都不代表业务能收包——如果 TCP backlog 满了、EventLoop 卡死、Redis 连接池耗尽,服务已不可用,但所有基础检测都过。这种场景得结合业务探活(比如定时发 mock 请求),否则秒级重启也救不回实际可用性。

















