You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel8/9/10 Docker部署下SIGTERM处理:调度器与Worker

Laravel调度器处理SIGTERM信号,避免容器关闭时启动新任务

一、Laravel队列Worker的SIGTERM处理现状

Laravel 8、9、10版本会处理队列Worker的SIGTERM信号,但根据Worker.php第185行的注释,Laravel仅针对当前Worker实例处理该信号:

// Finally, we will check to see if we have exceeded our memory limits or if
// the queue should restart based on other indications. If so, we'll stop
// this worker and let whatever is "monitoring" it restart the process.

如果不修改supervisor(或其他监控工具)使其识别SIGTERM并不再重启Worker,这个处理的效果很有限——因为Laravel要等Worker完成当前任务后才会停止。当然也可以在supervisor停止重启队列时,执行artisan queue:restart来优雅停止所有任务。

二、调度器的核心需求

我们需要实现:当收到SIGTERM信号(比如Docker容器关闭时),php artisan schedule:run不再启动任何新命令,避免容器在进程执行中途被终止,这在部署或缩容场景中非常关键。

三、现有方案的局限性

  • 将调度命令放入队列:虽然能解决问题,但会限制调度器只能处理队列任务,灵活性不足。
  • Symfony的ConsoleEvents::SIGNAL事件监听:由于schedule:run每分钟仅执行一次,执行窗口极窄,很可能错过比如第30秒发送的SIGTERM信号,无法有效拦截新任务启动。

四、可行实现方案:PCNTL信号拦截+全局状态控制

我们可以利用PHP的PCNTL扩展,在Console Kernel中监听SIGTERM信号,通过单例类记录状态,让调度器在状态标记为禁用时直接返回,不启动新任务。

步骤1:创建全局状态单例类

// app/SignalSingleton.php
namespace App;

class SignalSingleton
{
    public bool $schedulerIsEnabled = true;
}

步骤2:修改Console/Kernel.php处理信号并控制调度

// app/Console/Kernel.php
namespace App\Console;

use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Events\Dispatcher;
use Illuminate\Support\Facades\Log;
use App\SignalSingleton;

class Kernel extends ConsoleKernel
{
    public function __construct(Application $app, Dispatcher $events)
    {
        parent::__construct($app, $events);
        $this->app->singleton(SignalSingleton::class);

        // 检查PCNTL扩展是否加载,没加载则跳过信号处理
        if (!extension_loaded('pcntl')) {
            return;
        }

        // 启用异步信号处理
        pcntl_async_signals(true);
        // 监听SIGTERM信号,标记调度器为禁用状态
        pcntl_signal(SIGTERM, function (int $signo, mixed $siginfo): void {
            Log::info('收到SIGTERM信号,将停止启动新的调度任务');
            resolve(SignalSingleton::class)->schedulerIsEnabled = false;
        });
    }

    protected function schedule(\Illuminate\Console\Scheduling\Schedule $schedule): void
    {
        // 如果调度器已被禁用,直接返回,不执行任何任务
        if (!resolve(SignalSingleton::class)->schedulerIsEnabled) {
            return;
        }

        // 在这里编写你的正常调度任务
        // 示例:$schedule->command('inspire')->hourly();
        // ...
    }
}

注意事项

  • 该方案依赖PHP的pcntl扩展,需要确保运行环境已安装并启用该扩展。
  • 当容器收到SIGTERM信号后,Kernel会立即标记调度器状态为禁用,后续每次schedule:run执行时都会直接跳过任务启动逻辑,避免新任务在容器关闭前启动。

内容的提问来源于stack exchange,提问作者user7309871

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:13:28