Skip to content

队列

配置

Laravel 队列组件提供了一个统一的 API,跨越多种不同的队列服务。队列允许您推迟处理耗时的任务,例如发送电子邮件,直到稍后的时间,从而大大加快了对您应用程序的 Web 请求。

队列配置文件存储在 app/config/queue.php 中。在此文件中,您将找到与框架中包含的每个队列驱动程序的连接配置,包括 BeanstalkdIronMQAmazon SQSRedis 和同步(用于本地使用)驱动程序。

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

  • Beanstalkd: pda/pheanstalk ~2.0
  • Amazon SQS: aws/aws-sdk-php
  • IronMQ: iron-io/iron_mq

基本用法

将作业推送到队列

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

php
Queue::push('SendEmail', array('message' => $message));

定义作业处理程序

传递给 push 方法的第一个参数是应使用的处理作业的类的名称。第二个参数是应传递给处理程序的数据数组。作业处理程序应如下定义:

php
class SendEmail {

	public function fire($job, $data)
	{
		//
	}

}

请注意,唯一需要的方法是 fire,它接收一个 Job 实例以及推送到队列的数据数组。

指定自定义处理方法

如果您希望作业使用除 fire 以外的方法,可以在推送作业时指定该方法:

php
Queue::push('SendEmail@send', array('message' => $message));

为作业指定队列/管道

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

php
Queue::push('SendEmail@send', array('message' => $message), 'emails');

将相同的有效负载传递给多个作业

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

php
Queue::bulk(array('SendEmail', 'NotifyUser'), $payload);

延迟作业的执行

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

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

Queue::later($date, 'SendEmail@send', array('message' => $message));

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

lightbulb

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

删除已处理的作业

处理完作业后,必须通过 Job 实例上的 delete 方法将其从队列中删除:

php
public function fire($job, $data)
{
	// 处理作业...

	$job->delete();
}

将作业释放回队列

如果您希望将作业释放回队列,可以通过 release 方法实现:

php
public function fire($job, $data)
{
	// 处理作业...

	$job->release();
}

您还可以指定在释放作业之前等待的秒数:

php
$job->release(5);

检查运行尝试次数

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

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

访问作业 ID

您还可以访问作业标识符:

php
$job->getJobId();

队列闭包

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

将闭包推送到队列

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 4 队列功能,而无需运行任何守护进程或后台监听器。目前,推送队列仅由 Iron.io 驱动程序支持。在开始之前,请创建一个 Iron.io 帐户,并将您的 Iron 凭据添加到 app/config/queue.php 配置文件中。

注册推送队列订阅者

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

php
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 表中。失败的作业表名称可以通过 app/config/queue.php 配置文件进行配置。

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

php
php artisan queue:failed-table

您可以使用 --tries 开关在 queue:listen 命令中指定作业应尝试的最大次数:

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

如果您想注册一个事件,当队列作业失败时将被调用,您可以使用 Queue::failing 方法。此事件是通过电子邮件或 HipChat 通知您的团队的绝佳机会。

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

要查看所有失败的作业,您可以使用 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