FrankenPHP本身不直接管理PHP Worker进程生命周期,而是作为SAPI层转发请求;启用frankenphp-worker模式后,通过pcntl_async_signals和信号处理器实现优雅关闭,并需配合Docker/systemd正确透传SIGTERM。

FrankenPHP 本身不直接管理 PHP Worker 进程的生命周期(比如 Laravel Octane 那样的长生命周期模型),而是作为 SAPI 层,将请求转发给 PHP 应用。但当你用 frankenphp-worker 模式(即通过 frankenphp.Worker 启动自定义 worker)时,它会启动一个长期运行的 PHP 进程,并支持捕获系统信号(如 SIGTERM、SIGINT)来实现优雅关闭。
1. 在 worker 中注册信号处理器
核心是使用 pcntl_signal() 注册对 SIGTERM 和 SIGINT 的响应,并配合 pcntl_signal_dispatch() 或 pcntl_async_signals(true)(PHP 7.1+ 推荐)来确保信号能被及时处理。
示例代码(worker.php):
<?php // 启用异步信号处理(推荐)
pcntl_async_signals(true);
<p>$running = true;<p>// 捕获终止信号
pcntl_signal(SIGTERM, function (int $signo) use (&$running) {
echo "[INFO] Received SIGTERM, shutting down gracefully...\n";
$running = false;
});</p><p>pcntl_signal(SIGINT, function (int $signo) use (&$running) {
echo "[INFO] Received SIGINT, shutting down gracefully...\n";
$running = false;
});</p><p>// 可选:也处理 SIGHUP(比如配置重载场景)
pcntl_signal(SIGHUP, function (int $signo) {
echo "[INFO] Received SIGHUP, reloading config...\n";
// 实现你的配置重载逻辑
});</p><p>// 模拟 worker 主循环(例如消费队列、监听事件等)
while ($running) {
// ✅ 关键:定期检查信号并执行回调(即使用了 async_signals,某些场景仍建议主动 dispatch)
pcntl_signal_dispatch();</p><pre class="brush:php;toolbar:false;">// 执行一次工作单元(例如:从 Redis 队列 pop 一个任务)
$task = get_next_task();
if ($task !== null) {
handle_task($task);
}
// 避免忙轮询,加个轻量延时
usleep(10000); // 10ms}
// ✅ 优雅关闭阶段:完成当前任务、释放资源、关闭连接等 echo "[INFO] Waiting for current task to finish...\n"; // 如果有正在处理的任务,可加等待逻辑(例如设置超时)
echo "[INFO] Cleaning up resources...\n"; cleanup_resources(); // 例如:关闭数据库连接、释放文件锁、断开 Redis
echo "[INFO] Worker exited gracefully.\n";
2. 确保 FrankenPHP 正确发送信号
FrankenPHP 在收到外部终止指令(如 docker stop、systemctl stop 或 kill <pid></pid>)时,会向 worker 进程转发 SIGTERM —— 前提是 worker 是其子进程且未被 fork() 出去脱离关系。
✅ 注意事项:
- 不要在 worker 中调用
pcntl_fork()后让父进程退出,否则 FrankenPHP 将失去对 worker 的控制;保持主进程直系存活。 - 使用
frankenphp.Worker启动方式(非frankenphp.Server),确保 FrankenPHP 把它当 worker 管理。 - Docker 场景下,确保使用
init: true或tini作为 PID 1,避免信号被僵尸进程吞掉。
3. 配合 Docker / systemd 实现可靠终止
以 Docker Compose 为例,推荐配置:
services:
app:
image: your-frankenphp-app
init: true # 使用 tini 作为 init 进程,透传信号
stop_signal: SIGTERM
stop_grace_period: 30s # 给足时间完成优雅关闭
systemd unit 文件中应设置:
KillSignal=SIGTERM RestartPreventExitStatus=0 TimeoutStopSec=30
4. 调试与验证技巧
快速验证信号是否生效:
- 启动 worker 后,用
ps aux | grep worker.php找到 PID - 执行
kill -TERM <pid></pid>,观察控制台是否输出Received SIGTERM... - 若无反应,检查是否漏了
pcntl_async_signals(true)或pcntl_signal_dispatch() - 确认 PHP 编译时启用了
pcntl扩展:php -m | grep pcntl
不复杂但容易忽略的是信号注册时机和主循环中的 dispatch 调用 —— 它们共同决定了你的 worker 能否真正“优雅”停下来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











