workerman通过master进程监控并回收worker子进程实现故障恢复:master持续调用pcntl_waitpid捕获sigchld信号,及时拉起新worker;若master崩溃或未及时wait,则worker变为孤儿或僵尸进程。

pcntl_wait 没被及时调用,或主进程(Master)提前退出,是子进程变孤儿的直接原因。
Workerman 的 Master 进程本该始终存活,并通过 pcntl_wait 或 pcntl_waitpid 主动回收已退出的 Worker 子进程。一旦这个机制失效,退出的 Worker 就会变成僵尸;而如果 Master 进程自己先挂了,所有还在运行的 Worker 就立刻失去父进程——变成孤儿进程。
常见触发场景和对应表现:
-
start.php被手动 kill -9 或意外崩溃(比如未捕获的Fatal error),Master 进程直接终止,所有 Worker 父 PID 变成 1 - 使用
nohup php start.php start &启动,但 Workerman 未处理SIGHUP,终端断开后 Master 被系统终止 -
disable_functions中禁用了pcntl_wait或pcntl_signal,导致monitorWorkersForLinux内部的信号循环无法正常 dispatch 和 wait - systemd Unit 文件中
User=配置错误,Master 启动失败(如 pidFile 写入权限不足),看似启动成功实则几秒后静默退出,留下孤立的 Worker
为什么“长时间运行后”才暴露?
- 初期 Master 健康,子进程退出后能被正常回收;但某次异常(如内存溢出、扩展段错误)导致 Master 进程崩溃,之后再无进程管理能力
- 日志里可能只看到一条
exit with status 256(表示 PHP 崩溃),后续 Worker 就开始陆续变孤儿,ps aux | grep defunct会逐渐出现 Z 状态进程 - 若用
Worker::reloadGracefully()触发 reload,但代码里有阻塞操作(如sleep(10)在onWorkerStart中),旧 Master 可能卡在等待阶段,新 Master 启动后旧的还没彻底退出,造成短暂父子关系混乱
验证是否已存在孤儿进程:
- 执行
ps auxf,找 Worker 进程,看其 PPID 是否为 1 - 执行
ps aux | awk '$8 ~ /Z/ {print}'查僵尸进程(说明 Master 曾经还活着,但没及时 wait) - 检查
workerman.log最后几行,是否有Master process terminated或长时间没有worker xxx started日志
真正棘手的地方不在“怎么发现”,而在于:Master 崩溃后,它原本维护的 static::$_pidMap、static::$_pidsToRestart 等状态全部丢失,重启后的 Master 对之前那些“活着但无主”的 Worker 完全不可见——它们既不会被监控,也不会被清理,只能靠人工 kill 或系统 init 收养。











