我有一个向远程服务发送请求的队列。有时这项服务会进行维护。我希望所有队列任务在遇到这种情况时暂停并在10分钟内重试。我该如何实现?
答案 0 :(得分:4)
您可以使用Queue::looping()
事件侦听器暂停整个队列或连接(而不仅仅是单个作业类)。与其他方法不同,在队列暂停时,这不会将每个作业置于弹出/重新排队的周期,这意味着尝试次数不会增加。
文档内容如下:
在
looping
外观上使用Queue
方法,您可以指定 在工作程序尝试从中获取作业之前执行的回调 队列。
此不能很好地说明的是,如果回调返回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
属性将在启动工作进程时包含来自命令行的值,因此,如果您的工作进程正在检查多个队列(例如queue:work --queue=high,default
),则事件中queue
的值将为'high,default'
。
例如,如果您有一个要暂停的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 (('mail' == $event->queue) && (cache()->get('mail-queue-paused'))) {
return false;
}
});
}
这假定您在应用程序中的其他位置具有确定何时暂停队列的机制,我通过检查缓存中是否存在特定键来演示了这一点。
答案 1 :(得分:2)
<?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));
}
}
}