swoole 5 中协程异常需手动捕获,未处理会导致协程静默终止或worker崩溃;必须在每个协程入口及关键回调加try-catch,并设置全局异常处理器、配置熔断机制与强化日志可观测性。

在 Swoole 5 中,协程内未捕获的异常不会自动向上冒泡到 Worker 进程,但若未做任何防护,该协程会静默终止;而更危险的是:当异常发生在关键回调(如 onReceive、onRequest、onWorkerStart)中且未被包裹 try-catch,就可能触发 Worker 进程级崩溃——尤其在低版本兼容模式或配置不当场景下。
必须在协程入口加 try-catch
协程异常无法跨协程传播,也不能被父协程捕获。每个 go() 或协程回调都应视为独立错误边界:
- 所有
go(function () { ... })内部必须有顶层try/catch(\Throwable $e) - HTTP Server 的
onRequest、TCP Server 的onReceive等回调函数体,也需手动包裹(即使内部已启协程) - 避免只在子函数里捕获——异常可能发生在协程启动瞬间(如参数校验失败、连接初始化报错)
启用全局协程异常处理器
Swoole 5 提供了 Swoole\Coroutine\Scheduler::setExceptionHandler(),可捕获所有未被捕获的协程异常,是最后的兜底防线:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 它仅对「协程内抛出、且未被任何 try-catch 捕获」的异常生效
- 建议在
onWorkerStart中设置,确保每个 Worker 独立注册 - 处理逻辑应包含日志记录 + 可选告警,不建议在此处
exit或重启进程
use Swoole\Coroutine\Scheduler;
Swoole\Coroutine\run(function () {
Scheduler::setExceptionHandler(function (\Throwable $e) {
error_log(sprintf('[CRITICAL] Uncaught in coroutine: %s in %s:%d',
$e->getMessage(), $e->getFile(), $e->getLine()));
// 可上报 Sentry / Prometheus alert
});
go(function () {
throw new RuntimeException('no catch → hit handler');
});
});
配置 Worker 错误熔断与自动恢复
靠代码防护不能 100%杜绝意外,需结合进程层机制降低影响面:
- 设置
'max_request' => 3000:防止异常积累引发内存/状态污染后长期带病运行 - 启用
'reload_async' => true:平滑重启时不影响已有连接,降低异常 Worker 残留风险 - 监听
onWorkerError事件:捕获 Worker 异常退出信号(如致命错误、段错误),记录上下文并触发监控告警 - 配合
supervisor或systemd管理进程,实现进程崩溃后的自动拉起(注意避免雪崩重启)
日志与可观测性加固
异常静默失败最难排查,必须让问题“看得见”:
- 开启
swoole.display_errors = On和error_log配置,确保 PHP 层错误不丢失 - 在
onWorkerStart中调用ini_set('log_errors', 'On')并指定error_log文件路径 - 使用
Coroutine::set(['trace_flags' => SWOOLE_TRACE_COROUTINE])开启协程追踪,辅助定位异常发生时的协程栈 - 定期调用
swoole_memory_get_stats()+Coroutine::stats()输出到日志,建立基线用于异常时对比










