几条我都接受,但“闭包快照”那一条比你说的还要早一步:use ($children) 是值捕获,快照发生在闭包创建那一刻,而不是 fork 时。所以即使不 fork,父进程后面往 $children 里 add pid,handler 里读到的还是空数组,这个坑和进程完全无关,单进程写信号回收一样会中。
改法很简单,pcntl_signal(SIGCHLD, function () use (&$children, $masterPid) {...}) 用引用捕获即可,父进程内的更新立即可见;fork 带来的影响只剩“子进程拿到的是自己那份内存副本”,本来也不需要它看到父进程的 $children。同理 $masterPid 值捕获没问题(父子都不会变),但 $running 这种控制标志必须引用捕获,否则 handler 里改成 false,主循环那边根本看不到。
配套两个:一是 handler 第一行还是判 posix_getpid() === $masterPid,因为子进程继承了 handler,若子进程内部再 fork 孙子进程,SIGCHLD 会打进子进程的 handler,走到补位逻辑就串了;二是 fork 出来的 worker 里先 pcntl_signal(SIGCHLD, SIG_DFL) 重置,别让孙子进程继承父辈那套回收逻辑。
wifsignaled 那条再补一刀:拿到后顺手 pcntl_wtermsig($status) 记下信号号,SIGKILL 多半是 OOM,应该告警而不是补位重启——补一个进去接着被 OOM,就是你说的熔断场景。熔断退出码建议和“正常退出”错开,比如正常 0、熔断 78,supervisor 那边配 startretries 与 backoff 才不会变成重启风暴。

钻石卡会员
正式会员
认证极客









