Webman的process是常驻子进程而非多线程任务调度系统,无内置通信、反序列化、重试、超时及自动重启机制,需手动实现协议、容错与反馈。

Webman 本身不支持 PHP 多线程(pthreads 已废弃且与 Swoole/Workerman 运行时冲突),所谓“多线程任务”实际是常驻子进程(process)+ 手动通信的组合方案,不是开箱即用的异步任务系统。
为什么 process 不等于多线程任务调度
很多人看到 config/process.php 就以为能像 Swoole 的 $server->task() 那样发任务、等回调。但 Webman 的 process 只是启动一个独立 PHP 进程,它:
- 不监听任何端口,除非你显式配置
listen => 'text://0.0.0.0:12345' - 不会自动反序列化传入数据,
onMessage收到的是原始字符串,需手动json_decode() - 没有内置重试、超时、失败队列或任务状态反馈机制
- 进程崩溃后默认不自动重启,得加
'restart_on_fail' => true并配健康检查
如何让 process 真正跑起耗时任务
想用 process 处理耗时逻辑(比如导出报表、生成 PDF、调外部 API),必须自己补全协议层和容错逻辑:
- 约定请求格式:
{"cmd": "gen_report", "user_id": 123, "timeout": 30} - 在
onMessage开头强制设超时:set_time_limit($data['timeout'] ?? 15) - 所有外部调用必须带超时:Guzzle 的
'timeout' => 3.0、PDO 的PDO::ATTR_TIMEOUT、Redis 的timeout参数 - 执行完主动
$connection->send(json_encode(['status' => 'success', 'task_id' => $id])),别只 echo - 捕获全部异常并写日志:
error_log("Process error: " . $e->getMessage(), 3, __DIR__ . '/process_error.log')
常见卡死点和对应修复
积压不是因为并发不够,而是某条消息让整个 process 进程挂住。典型卡点:
立即学习“PHP免费学习笔记(深入)”;
-
file_get_contents('https://slow-api.com')—— 必须替换为 Guzzle 并设'connect_timeout' => 1.5, 'timeout' => 3.0 -
new PDO()直连数据库 —— 改用框架封装的连接池,确保复用连接且有超时 -
fopen('/huge_file.zip', 'w')写大文件 —— 改为分块写 +fflush()+ 检查磁盘空间 -
Redis::blpop()在 process 里误用 —— process 不该自己拉 Redis 队列,那是redis-queue插件干的事 - 日志写满磁盘导致
file_put_contents()阻塞 —— 定期轮转,用Monolog\Handler\RotatingFileHandler
process 和 redis-queue 插件怎么选
二者定位完全不同,混用反而增加运维复杂度:
- 用
redis-queue:适合标准异步任务(发邮件、写日志、通知推送),有失败队列、重试机制、并发控制,开箱即用 - 用
process:适合需要长连接、自定义协议、或必须脱离 HTTP 生命周期的场景(如串口通信中转、WebSocket 后台心跳维持) - 别把耗时 HTTP 调用塞进 process 再去调 Guzzle —— 这只是把阻塞从 HTTP 进程挪到另一个进程,没解决根本问题
真正要解堵塞,得先确认瓶颈在哪:是单条任务太慢,还是并发数压垮了 Redis 连接池,或是日志/磁盘/网络某处被卡住。process 只是工具,不是银弹。



















