如何暂停 Laravel 队列
How do you pause a Laravel queue
我有一个向远程服务发送请求的队列。有时此服务会进行维护。当遇到这种情况时,我希望所有队列任务都暂停并在 10 分钟后重试。我该如何实施?
<?php
namespace App\Jobs;
use ...
class SendRequest implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
const REMOTE_SERVER_UNAVAILABLE = 'remote_server_unavailable';
private $msg;
private $retryAfter;
public function __construct($msg)
{
$this->msg = $msg;
$this->retryAfter = 10;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(){
try {
// if we have tried sending the request and get a RemoteServerException, we will
// redispatch the job directly and return.
if(Cache::get(self::REMOTE_SERVER_UNAVAILABLE)) {
self::dispatch($this->msg)->delay(Carbon::now()->addMinutes($this->retryAfter));
return;
}
// send request to remote server
// ...
} catch (RemoteServerException $e) {
// set a cache value expires in 10 mins if not exists.
Cache::add(self::REMOTE_SERVER_UNAVAILABLE,'1', $this->retryAfter);
// if the remote service undergoes a maintenance, redispatch a new delayed job.
self::dispatch($this->msg)->delay(Carbon::now()->addMinutes($this->retryAfter));
}
}
}
您可以使用 Queue::looping()
事件侦听器来暂停整个队列或连接(而不仅仅是单个作业 class)。与其他方法不同,这将不会在队列暂停时将每个作业置于pop/requeue的循环中,这意味着尝试次数不会增加.
文档是这样说的:
Using the looping
method on the Queue
facade, you may specify
callbacks that execute before the worker attempts to fetch a job from
a queue.
这个 没有 很好地记录的是,如果回调 returns false
那么 the worker will not fetch another job。例如,这将阻止 default
队列从 运行:
Queue::looping(function (\Illuminate\Queue\Events\Looping $event) {
// $event->connectionName (e.g. "database")
// $event->queue (e.g. "default")
if ($event->queue == 'default') {
return false;
}
});
注意:事件的 queue
属性 将包含工作进程启动时命令行的值,因此如果您的工作进程正在检查多个队列(例如 artisan queue:work --queue=high,default
) 那么事件中 queue
的值将是 'high,default'
。作为预防措施,您可能希望用逗号分解字符串并检查 default
是否在列表中。
因此,例如,如果您想创建一个基本的 circuit breaker 来在邮件服务 returns 维护错误时暂停 mail
队列,那么您可以注册一个侦听器,例如这在你的 EventServiceProvider.php:
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
Queue::looping(function (\Illuminate\Queue\Events\Looping $event) {
if (($event->queue == 'mail') && (cache()->get('mail-queue-paused'))) {
return false;
}
});
}
这假设您在应用程序的其他地方有一种机制来检测适当的情况,并且在本例中,该机制需要为共享缓存中的 mail-queue-paused
键分配一个值(因为那是我的代码正在检查什么)。有更强大的解决方案,但在缓存中设置一个特定的众所周知的密钥(并使其自动过期)很简单并且可以达到预期的效果。
我有一个向远程服务发送请求的队列。有时此服务会进行维护。当遇到这种情况时,我希望所有队列任务都暂停并在 10 分钟后重试。我该如何实施?
<?php
namespace App\Jobs;
use ...
class SendRequest implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
const REMOTE_SERVER_UNAVAILABLE = 'remote_server_unavailable';
private $msg;
private $retryAfter;
public function __construct($msg)
{
$this->msg = $msg;
$this->retryAfter = 10;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(){
try {
// if we have tried sending the request and get a RemoteServerException, we will
// redispatch the job directly and return.
if(Cache::get(self::REMOTE_SERVER_UNAVAILABLE)) {
self::dispatch($this->msg)->delay(Carbon::now()->addMinutes($this->retryAfter));
return;
}
// send request to remote server
// ...
} catch (RemoteServerException $e) {
// set a cache value expires in 10 mins if not exists.
Cache::add(self::REMOTE_SERVER_UNAVAILABLE,'1', $this->retryAfter);
// if the remote service undergoes a maintenance, redispatch a new delayed job.
self::dispatch($this->msg)->delay(Carbon::now()->addMinutes($this->retryAfter));
}
}
}
您可以使用 Queue::looping()
事件侦听器来暂停整个队列或连接(而不仅仅是单个作业 class)。与其他方法不同,这将不会在队列暂停时将每个作业置于pop/requeue的循环中,这意味着尝试次数不会增加.
文档是这样说的:
Using the
looping
method on theQueue
facade, you may specify callbacks that execute before the worker attempts to fetch a job from a queue.
这个 没有 很好地记录的是,如果回调 returns false
那么 the worker will not fetch another job。例如,这将阻止 default
队列从 运行:
Queue::looping(function (\Illuminate\Queue\Events\Looping $event) {
// $event->connectionName (e.g. "database")
// $event->queue (e.g. "default")
if ($event->queue == 'default') {
return false;
}
});
注意:事件的 queue
属性 将包含工作进程启动时命令行的值,因此如果您的工作进程正在检查多个队列(例如 artisan queue:work --queue=high,default
) 那么事件中 queue
的值将是 'high,default'
。作为预防措施,您可能希望用逗号分解字符串并检查 default
是否在列表中。
因此,例如,如果您想创建一个基本的 circuit breaker 来在邮件服务 returns 维护错误时暂停 mail
队列,那么您可以注册一个侦听器,例如这在你的 EventServiceProvider.php:
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
Queue::looping(function (\Illuminate\Queue\Events\Looping $event) {
if (($event->queue == 'mail') && (cache()->get('mail-queue-paused'))) {
return false;
}
});
}
这假设您在应用程序的其他地方有一种机制来检测适当的情况,并且在本例中,该机制需要为共享缓存中的 mail-queue-paused
键分配一个值(因为那是我的代码正在检查什么)。有更强大的解决方案,但在缓存中设置一个特定的众所周知的密钥(并使其自动过期)很简单并且可以达到预期的效果。