Swoole中用户进程(UserProcess)的配置
Swoole中UserProcess必须通过addProcess()注册到Server,否则无法自动重启和信号监听,会生成僵尸进程。注册后Manager自动回收。与TaskWorker不同,它适合长周期后台任务,不受max_request限制,需自行处理热加载。
先说一个核心原则:UserProcess 必须通过 addProcess() 注册到 Swoole Server 中,否则它就成了“黑户”进程——既无法被自动重启,也收不到优雅关闭信号,更别提信号监听了。更严重的是,子进程退出后没人回收,僵尸进程就这么诞生了。而一旦正确注册,Swoole Manager 会自动处理 SIGCHLD,异步回收子进程,干干净净。

如何在 Swoole Server 中正确添加 UserProcess
关键一步:必须用 addProcess() 方法注册,绝对不能用 new SwooleProcess 之后直接调 start()。否则进程脱离主服务生命周期,自动重启、优雅关闭、信号监听一概失效。
常见错误写法长这样:
$p = new SwooleProcess(function($proc) { while(true) { sleep(1); }});$p->start(); // ❌ 错误:未纳入 Server 管理
正确姿势其实很简单:
- 在
on('Start')或on('WorkerStart')回调中调用$server->addProcess($process)。 $process必须是SwooleProcess实例,且它的回调函数不能阻塞主事件循环——比如别用无超时的sleep()。- 如果进程需要长期运行,建议用
tick()或after()来实现非阻塞定时逻辑,而不是死循环。
为什么 UserProcess 会变成僵尸进程
根源很简单:父进程(Swoole Manager)没有主动回收子进程的退出状态。当 UserProcess 自己 exit() 或异常终止,而主服务没监听 SIGCHLD,僵尸就留下了。
解决方法不是手动 wait()——那个会阻塞,正确的做法是利用 Swoole 内置机制:
- 只要通过
addProcess()添加,Swoole Manager 就会自动注册SIGCHLD处理器,异步回收子进程。 - 如果还是发现僵尸残留,先确认是否漏了
addProcess();再检查子进程退出前是否用了posix_kill($pid, SIGTERM)这类非标准退出方式。 - 验证方法:
ps aux | grep 'Z'或cat /proc/$pid/status | grep State。
UserProcess 与 TaskWorker 的核心区别
两者都干异步的活,但定位和资源模型完全不同:
- TaskWorker 是 Swoole 内置的固定角色进程,由
task_worker_num控制数量,只负责执行$server->task()投递的任务,共享 Server 配置和连接池。 - UserProcess 是完全自定义的独立进程,不参与请求响应链,不共享协程上下文——特别适合定时器、消息消费者、监控采集这类长周期后台任务。
- 混用有风险:在 UserProcess 里调用
$server->task()很可能失败(因为$server实例在子进程中不可用),正确做法是用管道或消息队列通信。
配置项对 UserProcess 的实际影响
大多数 server->set() 参数并不作用于 UserProcess,但以下三个例外值得注意:
max_request:只控制 Worker/TaskWorker 的重启,UserProcess 不受它限制——这也是它适合长任务的原因。daemonize:设为true时,UserProcess 随主服务一起转入后台;设为false则所有进程都在前台输出,方便调试。reload_async:热更新时默认不重启 UserProcess——它需要自己实现配置热加载,比如监听文件变更再重载业务类。
真正影响 UserProcess 行为的是你传给 SwooleProcess 构造函数的参数:$redirect_stdin_stdout 和 $pipe_type 决定了它能不能读写主服务的标准流、是否创建 IPC 管道。


































