web-chefs/queue-butler

Laravel Artisan 命令,通过调度器轻松运行作业队列,无需安装队列守护程序或安装监控器,可以有效地通过调度器从 cron 运行作业队列。


README

Latest Version on Packagist Software License Total Downloads Build Status

Laravel Artisan 命令,通过调度器轻松运行作业队列,无需安装队列守护程序或安装监控器。

这对于共享主机或您无法完全控制服务或托管基础设施的情况非常理想,您所能访问的只是一个 Cron。

版本支持矩阵

注意:PHP 版本支持与 Laravel PHP 支持相匹配。

Laravel 8+

从 Laravel 8 开始,使用 cron 调度器运行批量作业队列处理不再需要 QueueButler 包。

Laravel 8 引入了 max-jobsmax-time 选项,使得可以使用 Laravel 内置的 queue:work 命令。

$schedule->command('queue:work --queue=default,something,somethingelse --max-time=50 --max-jobs=100 --sleep=10 --tries=3 --backoff=60')
         ->everyMinute()
         ->runInBackground()
         ->withoutOverlapping(1);

要在 Laravel 8 中为同一队列运行多个队列工作进程,建议使用 --name= 选项。

$schedule->command('queue:work --name=job-worker-1 --queue=default,priority --max-time=280 --max-jobs=1000 --sleep=5 --tries=3 --backoff=180')
         ->everyMinute()
         ->runInBackground()
         ->withoutOverlapping(5);

$schedule->command('queue:work --name=job-worker-2 --queue=default,priority --max-time=280 --max-jobs=1000 --sleep=5 --tries=3 --backoff=180')
         ->everyMinute()
         ->runInBackground()
         ->withoutOverlapping(5);

安装

通过 Composer

$ composer require web-chefs/queue-butler

将服务提供者添加到 config/app.php

'providers' => [
   // Other Service Providers
   WebChefs\QueueButler\QueueButlerServiceProvider::class,
];

优点

  • 适用于任何支持 cron 的标准托管系统。
  • 具有容错能力,调度器会自动重新启动。
  • 新部署的代码将自动更新并运行下一次调度器运行时。
  • 可以根据作业的量度和类型创建多个队列批量命令。

使用方法

Artisan 命令

运行 queue:batch artisan 命令,支持与 queue:work 相同的许多选项。根据您的调度设置,需要设置两个额外的选项 time-limit(默认为 60 秒)和 'job-limit'(默认为 100)。

示例

运行 4 分钟 30 秒或 1000 个作业的批量,然后停止。

artisan queue:batch --time-limit=270 --job-limit=1000

调度器

在您的 App\Console\Kernel.php 中的 schedule() 方法中添加您的 queue:batch 命令。

由于作业队列处理是一个长期运行的过程,因此强烈建议设置 runInBackground(),否则每个 queue:batch 命令都会阻塞其后安排的所有预定项目。

调度器需要设置一个 Cron。有关调度器如何工作的详细信息,请参阅 Laravel 文档

队列批量生命周期

在安排队列的批量处理时,将安排一个命令在设定的时间间隔运行,持续设定的时间或作业数,然后退出。

不建议将超时和调度器间隔设置为相同的时间,因为您更有可能重叠调度器启动下一个批次的调用,但最后一个批次尚未完成。

最好考虑您的平均作业完成所需的时间,然后决定将批量结束时间与下一个开始时间有多接近。

这个批量命令之间的时间段没有作业正在处理,这是您的生命周期开销。

代码部署的影响

当队列批处理开始时,新的代码更改不会生效,您需要等待生命周期完成,然后在下一次运行时,新部署的代码将被运行,并反映更改。

错误很少发生,但在部署新代码时可能会发生。这发生在已经解析并加载到内存中的类包含了一个在部署后更改的类。在这种情况下,第一个类运行在旧版本上,第二个类运行在新版本上。

这是一个非常罕见的情况,但如果您想避免这种情况,可以将部署时间安排在生命周期开销窗口内。

withoutOverlapping() 和互斥锁缓存过期

建议使用 withoutOverlapping 调度函数,不要重叠相同的队列批处理命令。

当使用 withoutOverlapping 时,使用互斥锁缓存来跟踪正在运行的任务。默认缓存过期时间为 1440 分钟(24 小时)。

如果您的批处理过程被中断,调度器将在过期时间内忽略该任务,您将没有任务处理 24 小时。解决此问题的唯一方法是清除缓存或手动删除批处理过程的缓存条目。

为了防止长时间运行的缓存过期,建议将缓存过期时间与任务频率匹配,这样当批处理命令被中断时,调度器将在一个计划的生命周期内将其重新启动。

注意:请参阅 Laravel 5.3 的示例,该示例与后续版本不同。

基本示例

每分钟运行一次批处理,持续 50 秒或 100 个作业,在后台使用 runInBackground() 运行,然后停止。

为了防止重叠的批处理同时运行,使用 withoutOverlapping 匹配以分钟为单位的生命周期时间。

如果在队列中没有找到作业,在轮询队列以查找新作业之前,休眠 10 秒。

$schedule->command('queue:batch --queue=default,something,somethingelse --time-limit=50 --job-limit=100 --sleep=10')
         ->everyMinute()
         ->runInBackground()
         ->withoutOverlapping(1);

推荐示例

对于大多数用例,5 分钟的生命周期将很好地工作,通过创建一个运行时间为 4 分 40 秒或 1000 个作业的批处理命令,最大生命周期开销为 20 秒。

$schedule->command('queue:batch --time-limit=280 --job-limit=1000 --sleep=10')
         ->everyFiveMinutes()
         ->runInBackground()
         ->withoutOverlapping(5);

多个队列示例

如果您的应用程序正在使用多个队列处理大量作业,建议为每个队列设置不同的批处理调度命令。

// Low volume queues
$schedule->command('queue:batch --queue=default,something,somethingelse --time-limit=50 --job-limit=100 --sleep=10')
         ->everyMinute()
         ->runInBackground()
         ->withoutOverlapping(1);

// High volume dedicated "notifications" queue
$schedule->command('queue:batch --queue=notifications, --time-limit=175 --job-limit=500 --sleep=2')
         ->everyThreeMinutes()
         ->runInBackground()
         ->withoutOverlapping(1);

不建议向同一队列创建多个批处理,而是限制每个队列一个进程。另外,请参阅数据库驱动程序和死锁。

Laravel 5.3 示例

在 Laravel 5.3 中,我们需要直接设置 expiresAt 缓存过期互斥锁。

// Create Batch Job Queue Processor Task
$scheduledEvent = $schedule->command('queue:batch --time-limit=280 --job-limit=1000 --sleep=10');

// Match cache expiry with frequency
// Set cache mutex expiry to One min (default is 1440)
$scheduledEvent->expiresAt = 5;
$scheduledEvent->everyFiveMinutes()
               ->withoutOverlapping()
               ->runInBackground();

数据库队列驱动程序

当与 Queue Butler 一起使用时,Laravel 队列驱动程序是一个常见选项。唯一缺点是,MySQL 数据库支持的同时处理队列处理命令的数量有限,因为在处理新作业时,每个进程都将尝试锁定队列的顶端。

错误:SQLSTATE[40001]:序列化失败:1213 在尝试获取锁时发现死锁;尝试重新启动事务。

这些错误并不严重,因为作业将继续被处理,最大的影响将是进程等待时的作业处理速度。

我们不知道与使用 PostgreSQL 相关的类似问题。

标准

  • psr-1
  • psr-2
  • psr-4

变更日志

请参阅 CHANGELOG 了解最近更改的更多信息。

贡献

所有代码提交将仅作为拉取请求进行评估和接受。如果您有任何问题或发现任何错误,请随时打开一个问题。

鸣谢

许可证

MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件