Consumer进程异常退出时,先看日志里有没有FatalError;因其遇未捕获FatalError会静默崩溃,需在handle方法外层加try-catch(Throwable)并记录完整堆栈,同时校验消息体合法性、避免阻塞操作与内存泄漏。

Consumer进程异常退出时,先看日志里有没有FatalError
Hyperf的AMQP Consumer进程一旦遇到未捕获的FatalError(比如Class not found、Call to undefined method、内存耗尽触发的Allowed memory size exhausted),会直接崩溃退出,Swoole会记录类似worker(pid=12345, id=2) abnormal exit的日志,但不会打印堆栈——这是最典型的“静默挂掉”现象。
关键动作是:在Consumer类的handle方法最外层加try/catch(\Throwable $e),并强制记录完整堆栈到runtime/logs/;否则只靠ps aux | grep DemoConsumer看到进程消失,根本不知道哪行代码崩了。
- 别依赖Hyperf默认的全局异常处理器——它只处理HTTP请求链路,不兜底Consumer协程
- 确保
handle()里没用exit或die,它们会绕过所有异常捕获机制 - 如果用了
pcntl_fork或自定义协程启动逻辑,必须在每个子协程里单独注册register_shutdown_function
检查消息体反序列化是否触发致命错误
Consumer从RabbitMQ拉取消息后,默认用json_decode解析body。但如果消息里混入了PHP序列化字符串、UTF-8非法字节、或超长嵌套JSON,json_last_error()返回JSON_ERROR_DEPTH或JSON_ERROR_UTF8时,Hyperf不会自动跳过,而是让handle()收到null或部分解析结果,后续调用->xxx()就直接FatalError。
实操建议:
- 在
handle()开头加校验:if (!is_string($data) || !json_validate($data)) { $this->release(); return; }(json_validate是PHP 7.3+内置函数) - 避免在Consumer里直接
unserialize()——没有白名单机制,反序列化任意数据等于执行任意代码 - 生产环境禁用
display_errors=On,否则错误信息可能被当成响应体发回MQ,造成死循环
确认业务代码是否在协程中误用同步阻塞操作
Hyperf Consumer运行在Swoole协程内,但很多老代码仍习惯性调用file_get_contents、curl_exec、sleep甚至mysqli_query。这些操作会阻塞整个协程,若超时或失败,Swoole可能强制kill worker,表现为进程退出而非抛异常。
典型踩坑点:
-
Redis::connect()或new Redis()——必须用Co\Redis或DI容器注入的RedisFactory - 日志写文件用
file_put_contents——应改用LoggerInterface,它底层走协程IO - 数据库查询没走连接池——检查
config/autoload/db.php里pool.max_connections是否够用,不够时mysql_connect会卡住直到超时
内存泄漏导致OOM后进程被系统kill
Consumer长期运行时,如果在handle()里反复new大对象、缓存数据到静态变量、或没释放Co\Http\Client,worker内存会持续上涨。Linux OOM Killer发现内存超标后,会直接kill -9进程,日志里只剩abnormal exit,完全看不到PHP层错误。
验证方式:
- 用
watch -n 1 'ps aux --sort=-%mem | head -10'观察Consumer进程RSS内存变化趋势 - 在
handle()末尾加gc_collect_cycles()并记录memory_get_usage(true),确认是否稳定 - 临时把
config/autoload/process.php里的Consumer进程enable设为false,改用命令行php bin/hyperf.php amqp:consume DemoConsumer单次执行,看是否还崩溃——能复现说明是消息逻辑问题,否则大概率是长时协程资源累积
真正难排查的是那些只在特定消息内容下触发的FatalError,比如某个用户提交的JSON里带了不可见控制字符,或者第三方回调里传了PHP序列化字符串。这类问题不会出现在本地测试,只能靠线上日志+消息体快照还原现场。


















