队列服务
Configuration
队列允许您将耗时任务(例如发送电子邮件)的处理推迟到稍后时间,从而大大加快对您的应用程序的 Web 请求。
队列配置文件存放在config/queue.php
.在此文件中,您将找到包含的每个队列驱动程序的连接配置,例如数据库、Beanstalkd,IronMQ,亚马逊SQS 和Redis.
还有两个特殊的队列驱动程序可用:
- 这
sync
队列驱动程序在排队时立即运行作业。这对开发很有用。 - 这
null
队列驱动程序简单地丢弃排队的作业,因此它们永远不会被执行。
驱动程序先决条件
在使用 Amazon SQS、Beanstalkd、IronMQ 或 Redis 驱动程序之前,您需要安装驱动插件.
基本用法
将作业推送到队列中
要将新作业推送到队列中,请使用Queue::push
方法:
Queue::push('SendEmail', ['message' => $message]);
给的第一个参数push
method 是应该用于处理作业的类的名称。第二个参数是应该传递给处理程序的数据数组。作业处理程序应该这样定义:
class SendEmail
{
public function fire($job, $data)
{
//
}
}
请注意,唯一需要的方法是fire
, 它接收一个Job
实例以及数组data
被推到队列中。
指定自定义处理程序方法
如果您希望作业使用除fire
,您可以在推送作业时指定方法:
Queue::push('SendEmail@send', ['message' => $message]);
为作业指定队列名称
您还可以指定作业应发送到的队列/管道:
Queue::push('SendEmail@send', ['message' => $message], 'emails');
延迟作业的执行
有时您可能希望延迟排队作业的执行。例如,您可能希望在注册后 15 分钟向客户发送电子邮件的作业排队。您可以使用Queue::later
方法:
$date = Carbon::now()->addMinutes(15);
Queue::later($date, 'SendEmail', ['message' => $message]);
在这个例子中,我们使用Carbon 日期库来指定我们希望分配给作业的延迟。或者,您可以将希望延迟的秒数作为整数传递。
NOTE: Amazon SQS 服务的延迟限制为 900 秒(15 分钟)。
队列和模型
如果您的排队作业在其数据中采用模型,则只有模型的标识符将被序列化到队列中。当实际处理作业时,队列系统将自动从数据库中重新检索完整的模型实例。
这对您的应用程序来说是完全透明的,并且可以防止序列化完整模型实例可能出现的问题。
删除已处理的作业
处理完作业后,必须将其从队列中删除,这可以通过delete
上的方法Job
实例:
public function fire($job, $data)
{
// Process the job...
$job->delete();
}
将作业释放回队列
如果您希望将作业释放回队列中,您可以通过release
方法:
public function fire($job, $data)
{
// Process the job...
$job->release();
}
您还可以指定在发布作业之前等待的秒数:
$job->release(5);
检查运行尝试次数
如果在处理作业时发生异常,它将自动释放回队列中。您可以使用attempts
方法:
if ($job->attempts() > 3) {
//
}
将作业标记为失败
如果在运行作业时抛出异常并且重试次数耗尽,作业通常会被标记为失败,但您可能希望在某些情况下手动使作业失败。
要将作业标记为失败,您可以使用fail
方法:
$job->fail();
访问作业 ID
您还可以访问作业标识符:
$job->getJobId();
排队关闭
除了将作业类推入队列之外,您还可以为需要在当前请求周期之外执行的简单任务推送闭包。
将闭包推入队列
Queue::push(function () use ($id, $jobId) {
Account::delete($id);
$job = Job::get($jobId);
$job->delete();
});
NOTE: 而不是通过
use
指令,请考虑传递主键并从队列作业中重新拉出关联的模型。这通常可以避免意外的序列化行为。
使用 Iron.io 时推送队列,你应该采取额外的预防措施来排队闭包。接收队列消息的端点应检查令牌以验证请求实际上来自 Iron.io。例如,您的推送队列端点应该类似于:https://example.com/queue/receive?token=SecretToken
.然后,您可以在编组队列请求之前检查应用程序中秘密令牌的值。
运行队列工作者
冬天包括一些控制台命令 这将处理队列中的作业。
要在新作业被推入队列时处理它们,请运行queue:work
命令:
php artisan queue:work
一旦这个任务开始,它将继续运行直到它被手动停止。您可以使用进程监视器,例如Supervisor 以确保队列工作者不会停止运行。
队列工作进程将启动的应用程序状态存储在内存中。它们在启动后不会识别您的代码中的更改。部署更改时,重新启动队列工作程序。
处理单个作业
要仅处理队列中的第一个作业,请使用--once
选项:
php artisan queue:work --once
指定连接和队列
您还可以指定工作人员应使用哪个队列连接:
php artisan queue:work --once connection
您可以将逗号分隔的队列连接列表传递给work
设置队列优先级的命令:
php artisan queue:work --once --queue=high,low
在这个例子中,工作在high
队列将始终在移动到作业之前被处理low
队列。
指定作业超时参数
您还可以设置允许每个作业运行的时间长度(以秒为单位):
php artisan queue:work --once --timeout=60
指定队列休眠持续时间
此外,您可以指定在轮询新作业之前等待的秒数:
php artisan queue:work --once --sleep=5
请注意,如果队列中没有作业,队列只会“休眠”。如果有更多工作可用,队列将继续工作而不休眠。
守护进程队列工作者
默认情况下queue:work
将在不重新启动框架的情况下处理作业。与queue:work --once
命令,但需要在部署期间耗尽当前正在执行的作业的队列,这增加了复杂性。
要以守护进程模式启动队列工作者,只需省略--once
旗帜:
php artisan queue:work connection
php artisan queue:work connection --sleep=3
php artisan queue:work connection --sleep=3 --tries=3
您可以使用php artisan help queue:work
命令查看所有可用选项。
使用守护进程队列工作者进行部署
使用守护进程队列工作者部署应用程序的最简单方法是在部署开始时将应用程序置于维护模式。这可以使用后端设置区域来完成。一旦应用程序处于维护模式,Winter 将不会接受队列中的任何新作业,但会继续处理现有作业。
重启工作人员的最简单方法是在部署脚本中包含以下命令:
php artisan queue:restart
此命令将指示所有队列工作者在完成当前作业后重新启动。
NOTE: 此命令依赖于缓存系统来安排重启。默认情况下,APCu 不适用于 CLI 命令。如果您使用的是 APCu,请添加
apc.enable_cli=1
到您的 APCu 配置。
守护进程队列工作者的编码
守护进程队列工作者在处理每个作业之前不会重新启动平台。因此,您应该小心地在作业完成之前释放任何繁重的资源。例如,如果您正在使用 GD 库进行图像处理,您应该释放内存imagedestroy
当你完成时。
同样,您的数据库连接在被长时间运行的守护进程使用时可能会断开连接。您可以使用Db::reconnect
方法来确保你有一个新的连接。
使用系统守护进程
在将队列工作者作为守护进程运行时php artisan
有利于开发,在服务器上使用系统守护进程管理器来运行和监视队列工作程序将提供许多好处,例如自动重启、更好地记录到系统以及对配置的更多控制。
以下是常见系统守护进程管理器的两个示例。
Systemd
systemd
是在较新版本的 Linux 发行版中使用的通用进程管理器。它涵盖了一系列系统组件,并提供严格的控制和简单的配置。由于迄今为止它已预装在许多 Linux 发行版中,因此无需安装额外的软件即可使用它。
注册队列工作者服务
您可以通过在 CLI 终端中以 webhost 用户身份运行以下命令来注册新服务以运行队列工作程序:
systemctl --user edit --force --full queue-worker.service
这将打开一个终端编辑器,供您输入服务配置。一个典型的配置将由以下部分组成:
[Unit]
Description=Runs a queue worker for Winter CMS
OnFailure=failure-notify@%n.service
[Service]
Restart=always
# You can also use "Restart=on-failure" to restart only on a failure in the queue worker.
WorkingDirectory=/var/www/html
ExecStart=/usr/bin/php artisan queue:work
[Install]
WantedBy=default.target
您应该使用项目的根文件夹作为WorkingDirectory
定义。这ExecStart
定义应指定 PHP 可执行文件的直接路径,以及queue:work
您希望使用的命令和参数。
保存配置后,您需要启用它。
systemctl --user enable queue-worker.service
如果您对服务的配置进行任何更改,则必须重新加载配置systemd
,这可以通过运行以下命令来完成:
systemctl --user daemon-reload
启动/停止守护进程
要启动您的队列工作守护进程,只需运行以下命令:
systemctl --user start queue-worker.service
并停止队列工作守护进程:
systemctl --user stop queue-worker.service
最后,重新启动它:
systemctl --user restart queue-worker.service
NOTE: 如果您在通过 SSH 会话登录时运行以下命令,您的守护程序可能会在您注销后立即停止。您可以通过运行以下命令告诉您的操作系统使您的任何进程保持活动状态,替换为
<user>
运行服务的用户的占位符:loginctl enable-linger <user>
检查守护进程的状态
如果您想检查队列工作人员的状态,可以运行以下命令:
systemctl --user status queue-worker.service
默认情况下,systemd
将显示您的服务是否处于活动状态,并提供该服务的一小段日志。
您还可以通过查询获取完整日志journalctl
:
journalctl --user -u queue-worker.service
Supervisor
Supervisor 是 Linux 操作系统的进程监视器,会自动重启你的queue:work
如果失败则继续处理。要在 Ubuntu 上安装 Supervisor,您可以使用以下命令:
sudo apt-get install supervisor
配置主管
主管配置文件通常存储在/etc/supervisor/conf.d
目录。在此目录中,您可以创建任意数量的配置文件来指示主管如何监控您的进程。例如,让我们创建一个winter-worker.conf
启动和监视一个文件queue:work
过程:
[program:winter-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/winter/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=winter
numprocs=8
redirect_stderr=true
stdout_logfile=/path/to/winter/worker.log
在这个例子中,numprocs
指令将指示 Supervisor 运行 8queue:work
处理并监视所有这些,如果它们失败则自动重新启动它们。当然,你应该改变queue:work
命令指令的一部分以反映您所需的队列连接。这user
指令应更改为有权运行该命令的用户的名称。
首任主管
创建配置文件后,您可以更新 Supervisor 配置并使用以下命令启动进程:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start winter-worker:*
有关 Supervisor 的更多信息,请参阅主管文件.
失败的工作
由于事情并不总是按计划进行,有时您排队的作业会失败。别担心,它发生在我们最好的人身上!有一种方便的方法可以指定尝试作业的最大次数。在作业超过此尝试次数后,它将被插入到failed_jobs
桌子。失败的作业表名称可以通过配置config/queue.php
配置文件。
您可以使用--tries
打开queue:work
命令:
php artisan queue:work connection-name --tries=3
如果您想注册一个在队列作业失败时将被调用的事件,您可以使用Queue::failing
方法。此事件是通过电子邮件或其他第三方服务通知您的团队的绝佳机会。
Queue::failing(function($connection, $job, $data) {
//
});
你也可以定义一个failed
直接在队列作业类上的方法,允许您在发生故障时执行特定于作业的操作:
public function failed($data)
{
// Called when the job is failing...
}
的原始数组data
也将自动传递给失败的方法。
重试失败的作业
要查看所有失败的作业,您可以使用queue:failed
工匠命令:
php artisan queue:failed
这queue:failed
命令将列出作业 ID、连接、队列和失败时间。作业 ID 可用于重试失败的作业。例如,要重试 ID 为 5 的失败作业,应发出以下命令:
php artisan queue:retry 5
如果你想删除一个失败的作业,你可以使用queue:forget
命令:
php artisan queue:forget 5
要删除所有失败的作业,您可以使用queue:flush
命令:
php artisan queue:flush