Laravel任务调度支持秒级吗

wen PHP项目 2

本文目录导读:

Laravel任务调度支持秒级吗

  1. 方案一:使用 ->everyMinute() + 内部循环
  2. 方案二:使用自定义 Artisan 命令 + 无限循环
  3. 方案三:使用事件循环库(如 ReactPHP)
  4. ⚠️ 重要注意事项

Laravel 的任务调度不支持原生的秒级调度。

Laravel 的调度器 (schedule) 是基于 Cron 表达式的,标准的 Cron 表达式最小粒度是分钟,所以最低只能设置 ->everyMinute()(每分钟执行一次)。

如果你需要实现秒级的执行频率(例如每5秒、每30秒执行一次),需要通过以下变通方案实现:

使用 ->everyMinute() + 内部循环

最常用的方法,调度任务每分钟启动一次,然后在任务自身内部进行秒级循环。

示例:每10秒执行一次

  1. Kernel.php 中:

    protected function schedule(Schedule $schedule)
    {
        $schedule->job(new ProcessHighFequencyTasks)->everyMinute();
    }
  2. ProcessHighFequencyTasks Job 中:

    <?php
    namespace App\Jobs;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Bus\Dispatchable;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Queue\SerializesModels;
    class ProcessHighFequencyTasks implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
        public function handle()
        {
            $endTime = now()->addSeconds(60); // 运行59秒后停止,避免与下一次调度重叠
            while (now()->lessThan($endTime)) {
                // 需要执行的逻辑
                $this->doSomething();
                // 等待 10 秒
                sleep(10); // 注意:CLI 模式下 sleep 是安全的
                // 或者用 usleep(10000000); // 微秒级等待
            }
        }
        private function doSomething()
        {
            // 你的业务代码
        }
    }

使用自定义 Artisan 命令 + 无限循环

在自定义命令中实现一个守护进程式的循环,然后由 supervisor 管理。

示例:

// app/Console/Commands/ProcessRealTime.php
class ProcessRealTime extends Command
{
    protected $signature = 'app:process-real-time';
    public function handle()
    {
        while (true) {
            // 每5秒执行一次
            $this->call('some:other-command'); 
            sleep(5);
        }
    }
}

然后在 Kernel.php 中调用它,但通常不需要调度,而是用 Supervisor 直接监控这个命令:php artisan app:process-real-time

使用事件循环库(如 ReactPHP)

对于超高频(毫秒级)或需要非阻塞 I/O 的场景,可以结合 ReactPHP:

$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(1, function () {
    // 每秒执行一次
});
$loop->run();

⚠️ 重要注意事项

  1. 防止任务堆积:如果使用 ->everyMinute() + 内部循环,必须确保循环在下一次调度触发前结束,否则会导致进程数快速增长,最终耗尽服务器资源(内存泄漏或进程爆炸),上面的例子中设置了 60秒 超时(留1秒缓冲)。
  2. 使用队列:强烈建议将内部循环逻辑放入 Job 中并设置为 ShouldQueue,这样调度器只负责投递 Job,不会长时间占用 CLI 进程。
  3. 守护进程管理:如果使用无限循环方案,必须Supervisorsystemd 来管理进程,确保进程崩溃后自动重启。
  4. 性能考量:秒级任务对数据库、缓存、外部 API 的调用频率很高,注意做好幂等性设计和限流。
需求 推荐方案
每5-59秒一次 ->everyMinute() + 内部 sleep() 循环(最安全)
持续执行且可秒级控制 自定义命令 + Supervisor 管理守护进程
需要高精度非阻塞调用 使用 ReactPHP 等事件循环库

不要直接尝试修改 Laravel 核心以支持秒级 Cron,因为操作系统层面的 Cron 本身就不支持秒级,强行绕过会导致不可预测的问题。

抱歉,评论功能暂时关闭!