Swoole 的 swoole_signal 是协程信号重定向机制,非 Linux 信号简单封装;pcntl_signal 在协程中基本失效,因 Reactor 线程屏蔽信号且 Worker 不主动注册;swoole_signal 必须在 EventLoop 启动前于主线程注册,第三参数设 false 才禁用默认终止行为;Docker 中需 tini 避免 PID 1 劫持 SIGTERM;SIGTERM 实际由 Manager 进程处理并协调 Worker 退出,非原子广播,状态清理依赖 onShutdown 等后续流程。

Swoole 的 swoole_signal 不是 Linux 系统信号的简单封装,而是协程环境下的信号重定向机制——它把操作系统发给进程的原始信号,拦截后转为 PHP 层可安全调度的事件。
为什么 pcntl_signal 在 Swoole 协程里基本失效
协程运行时(如 Co\Http\Server)接管了线程调度和信号屏蔽逻辑。Swoole 默认在 Reactor 线程调用 swSignal_none() 阻塞全部信号,只留 Master/Manager 进程监听;Worker 进程不主动注册信号处理器,pcntl_signal 就收不到触发。
- 你在
onWorkerStart里调用pcntl_signal(SIGTERM, $cb),大概率不会执行——信号早被主线程截走或内核丢弃 - 即使启用
pcntl_async_signals(true),也仅对SIGUSR1/SIGUSR2/SIGTERM/SIGINT有限支持,且必须配合pcntl_signal_dispatch()主动轮询,无法依赖“自动回调” -
SIGHUP在 Swoole 中默认用于配置重载,覆盖它会导致 reload 失效
swoole_signal 的注册时机和作用域限制
swoole_signal 只在进入事件循环前、主线程(Manager 或主 Worker 的启动线程)中注册才有效。一旦 EventLoop 启动,再调用就返回失败,日志里会出现 SWOOLE_ERROR_UNREGISTERED_SIGNAL(707)。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 必须在
Server->start()之前完成注册,不能放在onWorkerStart或协程里 - 第三个参数设为
false才能禁用 Swoole 默认的终止行为(否则SIGTERM会直接杀掉 Worker) - Docker 容器中若用
sh或bash作 PID 1,SIGTERM会被 init 进程劫持,需改用tini作为入口
系统信号 vs Swoole 信号:谁在真正处理 SIGTERM
Linux 内核把 SIGTERM 发给整个进程组,但 Swoole 的 Master 进程收到后,并不会直接转发给每个 Worker;它通过共享内存或管道通知 Manager,再由 Manager 向 Worker 发送自定义退出指令——这中间有延迟、有状态同步,不是原子广播。
- 你注册的
swoole_signal(SIGTERM, $cb)回调,实际运行在 Manager 进程,不是 Worker 进程 - Worker 进程响应退出靠的是 Manager 的
kill -USR2或内部消息,不是原生SIGTERM - 所以不要在回调里直接调
$server->shutdown()——它只对当前进程有效,其他 Worker 还在跑
真正容易被忽略的是:信号处理不是“收到就停”,而是一套跨进程的状态协商。连接是否清理干净、定时器是否取消、Task 进程是否等待完成——这些都不在信号回调里发生,而在后续的 onShutdown、onWorkerExit 和主循环检测中逐步推进。任何跳过状态检查、强行 close fd 或 exit 的操作,都会导致 Connection reset by peer 或 SWOOLE_ERROR_SESSION_CLOSED。

















