use Illuminate\Queue\Middleware\SkipIfBatchCancelled;
* 获取任务应通过的中间件。
public function middleware(): array
return [new SkipIfBatchCancelled];
批处理失败
当批处理任务失败时,将调用 catch
回调(如果已分配)。此回调仅针对批处理中失败的第一个任务调用。
当批处理中的某个任务失败时,Laravel 会自动将该批处理标记为「已取消」。如果你愿意,你可以禁用此行为,以便任务失败不会自动将批处理标记为已取消。这可以通过在调度批处理时调用 allowFailures
方法来完成:
$batch = Bus::batch([
])->then(function (Batch $batch) {
})->allowFailures()->dispatch();
重试失败的批处理任务
为方便起见,Laravel 提供了一个 queue:retry-batch
Artisan 命令,允许你轻松重试给定批次的所有失败任务。 queue:retry-batch
命令接受应该重试失败任务的批处理的 UUID:
php artisan queue:retry-batch 32dbc76c-4f82-4749-b610-a639fe0099b5
如果不进行修剪,job_batches
表可以非常快速地积累记录。为了缓解这种情况,你应该 schedule queue:prune-batches
Artisan 命令每天运行:
$schedule->command('queue:prune-batches')->daily();
默认情况下,将修剪所有超过 24 小时的已完成批次。你可以在调用命令时使用 hours
选项来确定保留批处理数据的时间。例如,以下命令将删除 48 小时前完成的所有批次:
$schedule-
>command('queue:prune-batches --hours=48')->daily();
有时,你的 jobs_batches
表可能会累积从未成功完成的批次的批次记录,例如任务失败且该任务从未成功重试的批次。 你可以使用 unfinished
选项指示 queue:prune-batches
命令修剪这些未完成的批处理记录:
$schedule->command('queue:prune-batches --hours=48 --unfinished=72')->daily();
同样,你的 jobs_batches
表也可能会累积已取消批次的批次记录。 你可以使用 cancelled
选项指示 queue:prune-batches
命令修剪这些已取消的批记录:
$schedule->command('queue:prune-batches --hours=48 --cancelled=72')->daily();
除了将任务类分派到队列之外,你还可以分派一个闭包。这对于需要在当前请求周期之外执行的快速、简单的任务非常有用。当向队列分派闭包时,闭包的代码内容是加密签名的,因此它不能在传输过程中被修改:
$podcast = App\Podcast::find(1);
dispatch(function () use ($podcast) {
$podcast->publish();
});
使用 catch
方法,你可以提供一个闭包,如果排队的闭包在耗尽所有队列的配置的重试次数 后未能成功完成,则应执行该闭包:
use Throwable;
dispatch(function () use ($podcast) {
$podcast->publish();
})->catch(function (Throwable $e) {
});
注意
由于 catch
回调由 Laravel 队列稍后序列化并执行,因此你不应在 catch
回调中使用 $this
变量。
运行队列工作者
<code>queue:work</code> 命令
Laravel 包含一个 Artisan 命令,该命令将启动队列进程并在新任务被推送到队列时处理它们。 你可以使用 queue:work
Artisan 命令运行任务进程。请注意,一旦 queue:work
命令启动,它将继续运行,直到手动停止或关闭终端:
php artisan queue:work
技巧
要保持 queue:work
进程在后台永久运行,你应该使用 Supervisor 等进程监视器来确保队列工作进程不会停止运行。
如果你希望处理的任务 ID 包含在命令的输出中,则可以在调用 queue:work
命令时包含 -v 标志:
php artisan queue:work -v
请记住,队列任务工作者是长期存在的进程,并将启动的应用程序状态存储在内存中。 因此,他们在启动后不会注意到你的代码库中的更改。 因此,在你的部署过程中,请务必重新启动你的任务队列进程。 此外,请记住,你的应用程序创建或修改的任何静态状态都不会在任务启动之间自动重置。
或者,你可以运行 queue:listen
命令。 使用 queue:listen
命令时,当你想要重新加载更新后的代码或重置应用程序状态时,无需手动重启 worker; 但是,此命令的效率明显低于 queue:work
命令:
php artisan queue:listen
运行多个队列进程
要将多个 worker 分配到一个队列并同时处理任务,你应该简单地启动多个 queue:work
进程。 这可以通过终端中的多个选项卡在本地完成,也可以使用流程管理器的配置设置在生产环境中完成。 使用 Supervisor 时,你可以使用 numprocs
配置值。
指定连接 & 队列
你还可以指定工作人员应使用哪个队列连接。 传递给 work
命令的连接名称应对应于 config/queue.php
配置文件中定义的连接之一:
php artisan queue:work redis
默认情况下,queue:work
命令只处理给定连接上默认队列的任务。 但是,你可以通过仅处理给定连接的特定队列来进一步自定义你的队列工作者。 例如,如果你的所有电子邮件都在你的 redis
队列连接上的 emails
队列中处理,你可以发出以下命令来启动只处理该队列的工作程序:
php artisan queue:work redis --queue=emails
Processing A Specified Number Of Jobs
--once
选项可用于指定进程仅处理队列中的单个任务
php artisan queue:work --once
--max-jobs
选项可用于指示 worker 处理给定数量的任务然后退出。 此选项在与 Supervisor 结合使用时可能很有用,这样你的工作人员在处理给定数量的任务后会自动重新启动,释放他们可能积累的任何内存:
php artisan queue:work --max-jobs=1000
处理所有排队的任务然后退出
--stop-when-empty
选项可用于指定进程处理所有作业,然后正常退出。如果你希望在队列为空后关闭容器,则此选项在处理 Docker 容器中的 Laravel 队列时很有用
php artisan queue:work --stop-when-empty
在给定的秒数内处理任务
--max-time
选项可用于指示进程给定的秒数内处理作业,然后退出。 当与 Supervisor 结合使用时,此选项可能很有用,这样你的工作人员在处理作业给定时间后会自动重新启动,释放他们可能积累的任何内存:
php artisan queue:work --max-time=3600
进程睡眠时间
当队列中有任务可用时,进程将继续处理作业,而不会在它们之间产生延迟。但是,sleep
选项决定了如果没有可用的新任务,进程将 sleep
多少秒。 睡眠时,进程不会处理任何新的作业 - 任务将在进程再次唤醒后处理。
php artisan queue:work --sleep=3
资源注意事项
守护进程队列在处理每个任务之前不会 reboot
框架。因此,你应该在每个任务完成后释放所有繁重的资源。例如,如果你正在使用 GD 库进行图像处理,你应该在处理完图像后使用 imagedestroy
释放内存。
队列优先级
有时你可能希望优先处理队列的处理方式。例如,在 config/queue.php
配置文件中,你可以将 redis
连接的默认 queue
设置为 low
。 但是,有时你可能希望将作业推送到 high
优先级队列,如下所示:
dispatch((new Job)->onQueue('high'));
要启动一个进程,在继续处理 low
队列上的任何任务之前验证所有 high
队列任务是否已处理,请将队列名称的逗号分隔列表传递给 work
命令:
php artisan queue:work --queue=high,low
队列进程 & 部署
由于队列任务是长期存在的进程,如果不重新启动,他们不会注意到代码的更改。因此,使用队列任务部署应用程序的最简单方法是在部署过程中重新启动任务。你可以通过发出 queue:restart
命令优雅地重新启动所有进程:
php artisan queue:restart
此命令将指示所有队列进程在处理完当前任务后正常退出,以免丢失现有任务。由于队列任务将在执行 queue:restart
命令时退出,你应该运行诸如 Supervisor 之类的进程管理器来自动重新启动队列任务。
注意
队列使用 cache 来存储重启信号,因此你应该在使用此功能之前验证是否为你的应用程序正确配置了缓存驱动程序。
任务到期 & 超时
在config/queue.php
配置文件中,每个队列连接都定义了一个retry_after
选项。该选项指定队列连接在重试正在处理的作业之前应该等待多少秒。例如,如果retry_after
的值设置为90
,如果作业已经处理了90秒而没有被释放或删除,则该作业将被释放回队列。通常,你应该将retry_after
值设置为作业完成处理所需的最大秒数。
警告
唯一不包含 retry_after
值的队列连接是Amazon SQS。SQS将根据AWS控制台内管理的 默认可见性超时 重试作业。
queue:work
Artisan命令公开了一个--timeout
选项。默认情况下,--timeout
值为60秒。如果任务的处理时间超过超时值指定的秒数,则处理该任务的进程将退出并出现错误。通常,工作程序将由 你的服务器上配置的进程管理器 自动重新启动:
php artisan queue:work --timeout=60
retry_after
配置选项和 --timeout
CLI 选项是不同的,但它们协同工作以确保任务不会丢失并且任务仅成功处理一次。
警告
--timeout
值应始终比 retry_after
配置值至少短几秒钟。 这将确保处理冻结任务的进程始终在重试任务之前终止。 如果你的 --timeout
选项比你的 retry_after
配置值长,你的任务可能会被处理两次。
Supervisor 配置
在生产中,你需要一种方法来保持 queue:work
进程运行。 queue:work
进程可能会因多种原因停止运行,例如超过 worker 超时或执行 queue:restart
命令。
出于这个原因,你需要配置一个进程监视器,它可以检测你的 queue:work
进程何时退出并自动重新启动它们。此外,进程监视器可以让你指定要同时运行多少个 queue:work
进程。Supervisor 是 Linux 环境中常用的进程监视器,我们将在下面的文档中讨论如何配置它。
安装 Supervisor
Supervisor 是 Linux 操作系统的进程监视器,如果它们失败,它将自动重新启动你的 queue:work
进程。要在 Ubuntu 上安装 Supervisor,你可以使用以下命令:
sudo apt-get install supervisor
注意
如果你自己配置和管理 Supervisor 听起来很费力,请考虑使用 Laravel Forge,它会自动为你的生产 Laravel 项目安装和配置 Supervisor。
配置 Supervisor
Supervisor 配置文件通常存储在 /etc/supervisor/conf.d
目录中。在这个目录中,你可以创建任意数量的配置文件来指示 Supervisor 应该如何监控你的进程。例如,让我们创建一个启动和监控 queue:work
进程的 laravel-worker.conf
文件:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log
stopwaitsecs=3600
在这个例子中,numprocs
指令将指示 Supervisor 运行 8 个 queue:work
进程并监控所有进程,如果它们失败则自动重新启动它们。你应该更改配置的「命令」指令以反映你所需的队列连接和任务选项。
警告
你应该确保 stopwaitsecs
的值大于运行时间最长的作业所消耗的秒数。否则,Supervisor 可能会在作业完成处理之前将其终止。
开始 Supervisor
创建配置文件后,你可以使用以下命令更新 Supervisor 配置并启动进程:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
有关 Supervisor 的更多信息,请参阅 Supervisor 文档。
处理失败的任务
有时,你队列的任务会失败。别担心,事情并不总是按计划进行! Laravel 提供了一种方便的方法来 指一个任务应该尝试的最大次数。在异步任务超过此尝试次数后,它将被插入到 failed_jobs
数据库表中。 失败的 同步调度的任务 不存储在此表中,它们的异常由应用程序立即处理。
创建 failed_jobs
表的迁移通常已经存在于新的 Laravel 应用程序中。但是,如果你的应用程序不包含此表的迁移,你可以使用 queue:failed-table
命令来创建迁移:
php artisan queue:failed-table
php artisan migrate
运行 queue worker 进程时,你可以使用 queue:work
命令上的 --tries
开关指定任务应尝试的最大次数。如果你没有为 --tries
选项指定值,则作业将仅尝试一次或与任务类的 $tries
属性指定的次数相同:
php artisan queue:work redis --tries=3
使用 --backoff
选项,你可以指定 Laravel 在重试遇到异常的任务之前应该等待多少秒。默认情况下,任务会立即释放回队列,以便可以再次尝试:
php artisan queue:work redis --tries=3 --backoff=3
如果你想配置 Laravel 在重试每个任务遇到异常的任务之前应该等待多少秒,你可以通过在你的任务类上定义一个 backoff
属性来实现:
* 重试任务前等待的秒数
* @var int
public $backoff = 3;