Skip to content

队列

配置

Laravel 队列组件在各种不同的队列服务中提供了统一的 API。队列允许您将耗时的任务(如发送电子邮件)的处理推迟到稍后进行,从而大大加快应用程序的 Web 请求速度。

队列配置文件存储在 config/queue.php 中。在此文件中,您将找到框架中包含的每个队列驱动程序的连接配置,其中包括数据库、BeanstalkdIronMQAmazon SQSRedis、null 和同步(用于本地使用)驱动程序。null 队列驱动程序只是简单地丢弃排队的任务,因此它们永远不会运行。

队列数据库表

为了使用 database 队列驱动程序,您需要一个数据库表来保存任务。要生成创建此表的迁移,请运行 queue:table Artisan 命令:

php
php artisan queue:table

其他队列依赖项

以下是列出的队列驱动程序所需的依赖项:

  • Amazon SQS: aws/aws-sdk-php
  • Beanstalkd: pda/pheanstalk ~3.0
  • IronMQ: iron-io/iron_mq ~1.5
  • Redis: predis/predis ~1.0

基本用法

将任务推送到队列

应用程序的所有可排队任务都存储在 App\Commands 目录中。您可以使用 Artisan CLI 生成一个新的排队命令:

php
php artisan make:command SendEmail --queued

要将新任务推送到队列,请使用 Queue::push 方法:

php
Queue::push(new SendEmail($message));
lightbulb

在此示例中,我们直接使用 Queue facade;然而,通常您会通过 Command Bus 来调度排队命令。我们将在整个页面中继续使用 Queue facade;然而,也要熟悉命令总线,因为它用于调度应用程序的排队和同步命令。

默认情况下,make:command Artisan 命令生成一个“自处理”命令,这意味着在命令本身中添加了一个 handle 方法。当队列执行任务时,将调用此方法。您可以在 handle 方法中类型提示您需要的任何依赖项,服务容器 将自动注入它们:

php
public function handle(UserRepository $users)
{
	//
}

如果您希望命令有一个单独的处理程序类,您应该在 make:command 命令中添加 --handler 标志:

php
php artisan make:command SendEmail --queued --handler

生成的处理程序将放置在 App\Handlers\Commands 中,并将从 IoC 容器中解析。

为任务指定队列/管道

您还可以指定任务应发送到的队列/管道:

php
Queue::pushOn('emails', new SendEmail($message));

将相同的负载传递给多个任务

如果您需要将相同的数据传递给多个队列任务,可以使用 Queue::bulk 方法:

php
Queue::bulk([new SendEmail($message), new AnotherCommand]);

延迟任务的执行

有时您可能希望延迟排队任务的执行。例如,您可能希望在用户注册后 15 分钟发送一封电子邮件。您可以使用 Queue::later 方法实现此目的:

php
$date = Carbon::now()->addMinutes(15);

Queue::later($date, new SendEmail($message));

在此示例中,我们使用 Carbon 日期库来指定我们希望分配给任务的延迟。或者,您可以将要延迟的秒数作为整数传递。

lightbulb

Amazon SQS 服务的延迟限制为 900 秒(15 分钟)。

队列和 Eloquent 模型

如果您的排队任务在其构造函数中接受一个 Eloquent 模型,则只有模型的标识符会被序列化到队列中。当任务实际处理时,队列系统将自动从数据库中重新检索完整的模型实例。这对您的应用程序来说是完全透明的,并防止了序列化完整 Eloquent 模型实例时可能出现的问题。

删除已处理的任务

一旦您处理了一个任务,它必须从队列中删除。如果在执行任务期间没有抛出异常,这将自动完成。

如果您希望手动 deleterelease 任务,Illuminate\Queue\InteractsWithQueue trait 提供了对队列任务 releasedelete 方法的访问。release 方法接受一个值:您希望等待的秒数,直到任务再次可用。

php
public function handle(SendEmail $command)
{
	if (true)
	{
		$this->release(30);
	}
}

将任务释放回队列

如果在处理任务时抛出异常,它将自动释放回队列,以便可以再次尝试。任务将继续释放,直到达到应用程序允许的最大尝试次数。最大尝试次数由 queue:listenqueue:work Artisan 命令中使用的 --tries 开关定义。

检查运行尝试次数

如果在处理任务时发生异常,它将自动释放回队列。您可以使用 attempts 方法检查已尝试运行任务的次数:

php
if ($this->attempts() > 3)
{
	//
}
lightbulb

您的命令/处理程序必须使用 Illuminate\Queue\InteractsWithQueue trait 才能调用此方法。

队列闭包

您还可以将闭包推送到队列。这对于需要排队的快速简单任务非常方便:

将闭包推送到队列

php
Queue::push(function($job) use ($id)
{
	Account::delete($id);

	$job->delete();
});
lightbulb

而不是通过 use 指令将对象提供给排队的闭包,考虑传递主键并在队列任务中重新提取关联的模型。这通常可以避免意外的序列化行为。

使用 Iron.io 推送队列 时,您应该在队列闭包时格外小心。接收队列消息的端点应检查令牌以验证请求确实来自 Iron.io。例如,您的推送队列端点应类似于:https://yourapp.com/queue/receive?token=SecretToken。然后,您可以在应用程序中检查秘密令牌的值,然后再编排队列请求。

运行队列监听器

Laravel 包含一个 Artisan 任务,该任务将在新任务推送到队列时运行。您可以使用 queue:listen 命令运行此任务:

启动队列监听器

php
php artisan queue:listen

您还可以指定监听器应使用的队列连接:

php
php artisan queue:listen connection

请注意,一旦此任务启动,它将继续运行,直到手动停止。您可以使用诸如 Supervisor 之类的进程监视器来确保队列监听器不会停止运行。

您可以将队列连接的逗号分隔列表传递给 listen 命令以设置队列优先级:

php
php artisan queue:listen --queue=high,low

在此示例中,high 连接上的任务将始终在处理 low 连接上的任务之前处理。

指定任务超时参数

您还可以设置每个任务应允许运行的时间长度(以秒为单位):

php
php artisan queue:listen --timeout=60

指定队列休眠时间

此外,您可以指定在轮询新任务之前等待的秒数:

php
php artisan queue:listen --sleep=5

请注意,队列仅在队列上没有任务时“休眠”。如果有更多任务可用,队列将继续处理它们而不休眠。

处理队列上的第一个任务

要仅处理队列上的第一个任务,您可以使用 queue:work 命令:

php
php artisan queue:work

守护进程队列工作者

queue:work 还包括一个 --daemon 选项,用于强制队列工作者在不重新启动框架的情况下继续处理任务。这与 queue:listen 命令相比,显著减少了 CPU 使用率,但增加了在部署期间需要清空当前执行任务的队列的复杂性。

要以守护进程模式启动队列工作者,请使用 --daemon 标志:

php
php artisan queue:work connection --daemon

php artisan queue:work connection --daemon --sleep=3

php artisan queue:work connection --daemon --sleep=3 --tries=3

如您所见,queue:work 命令支持大多数 queue:listen 可用的选项。您可以使用 php artisan help queue:work 命令查看所有可用选项。

使用守护进程队列工作者进行部署

使用守护进程队列工作者部署应用程序的最简单方法是在部署开始时将应用程序置于维护模式。这可以通过 php artisan down 命令完成。一旦应用程序处于维护模式,Laravel 将不再接受队列上的新任务,但会继续处理现有任务。

重新启动工作者的最简单方法是在部署脚本中包含以下命令:

php
php artisan queue:restart

此命令将指示所有队列工作者在完成当前任务后重新启动。

lightbulb

此命令依赖于缓存系统来安排重启。默认情况下,APCu 不适用于 CLI 命令。如果您使用 APCu,请在 APCu 配置中添加 apc.enable_cli=1

为守护进程队列工作者编写代码

守护进程队列工作者在处理每个任务之前不会重新启动框架。因此,您应该小心在任务完成之前释放任何重资源。例如,如果您使用 GD 库进行图像处理,完成后应使用 imagedestroy 释放内存。

同样,您的数据库连接可能会在长时间运行的守护进程中断开。您可以使用 DB::reconnect 方法确保您有一个新的连接。

推送队列

推送队列允许您在不运行任何守护进程或后台监听器的情况下利用强大的 Laravel 5 队列功能。目前,推送队列仅由 Iron.io 驱动程序支持。在开始之前,创建一个 Iron.io 帐户,并将您的 Iron 凭据添加到 config/queue.php 配置文件中。

注册推送队列订阅者

接下来,您可以使用 queue:subscribe Artisan 命令注册一个 URL 端点,该端点将接收新推送的队列任务:

php
php artisan queue:subscribe queue_name queue/receive

php artisan queue:subscribe queue_name http://foo.com/queue/receive

现在,当您登录到 Iron 仪表板时,您将看到新的推送队列以及订阅的 URL。您可以将任意数量的 URL 订阅到给定队列。接下来,为您的 queue/receive 端点创建一个路由,并返回 Queue::marshal 方法的响应:

php
Route::post('queue/receive', function()
{
	return Queue::marshal();
});

marshal 方法将负责触发正确的任务处理程序类。要将任务推送到推送队列,只需使用与常规队列相同的 Queue::push 方法。

失败的任务

由于事情并不总是按计划进行,有时您的排队任务会失败。别担心,这种情况发生在最优秀的人身上!Laravel 提供了一种方便的方法来指定任务应尝试的最大次数。在任务超过此尝试次数后,它将被插入到 failed_jobs 表中。失败任务表名可以通过 config/queue.php 配置文件进行配置。

要为 failed_jobs 表创建迁移,您可以使用 queue:failed-table 命令:

php
php artisan queue:failed-table

您可以使用 queue:listen 命令上的 --tries 开关指定任务应尝试的最大次数:

php
php artisan queue:listen connection-name --tries=3

如果您希望注册一个事件,该事件将在队列任务失败时调用,您可以使用 Queue::failing 方法。此事件是通过电子邮件或 HipChat 通知您的团队的绝佳机会。

php
Queue::failing(function($connection, $job, $data)
{
	//
});

您还可以直接在队列任务类上定义一个 failed 方法,允许您在发生故障时执行特定于任务的操作:

php
public function failed()
{
	// 当任务失败时调用...
}

如果您的任务不是自处理的,并且有一个单独的处理程序类,则需要在处理程序类中定义 failed 方法。

重试失败的任务

要查看所有失败的任务,您可以使用 queue:failed Artisan 命令:

php
php artisan queue:failed

queue:failed 命令将列出任务 ID、连接、队列和失败时间。任务 ID 可用于重试失败的任务。例如,要重试 ID 为 5 的失败任务,应发出以下命令:

php
php artisan queue:retry 5

如果您希望删除失败的任务,可以使用 queue:forget 命令:

php
php artisan queue:forget 5

要删除所有失败的任务,您可以使用 queue:flush 命令:

php
php artisan queue:flush