Laravel队列速率限制或限制

时间:2017-11-20 19:28:02

标签: laravel laravel-5 queue laravel-queue

我正在处理一个需要从第三方服务器获取数据的应用程序,该服务器每秒允许最多1个请求。

现在,所有请求都作为工作发送,我正在尝试实施Laravel" Rate Limiting"每秒释放1个工作,但无法弄清楚为什么要实施它,网上没有真实的例子。

有没有人实现它?

有任何暗示吗?

6 个答案:

答案 0 :(得分:1)

我是mxl/laravel-queue-rate-limit Composer软件包的作者。

它允许您在不使用Redis的情况下为特定队列上的作业限制率。

  1. 通过以下方式安装:

    $ composer require mxl/laravel-queue-rate-limit:^1.0
    
  2. 此软件包与Laravel 5.5+兼容,并使用auto-discovery功能将MichaelLedin\LaravelQueueRateLimit\QueueServiceProvider::class添加到提供程序。

  3. 将速率限制设置添加到config/queue.php

    'rateLimit' => [
        'mail' => [
            'allows' => 1,
            'every' => 5
        ]
    ]
    

    这些设置允许每5秒在mail队列上运行1个作业。 确保将默认队列驱动程序(default中的config/queue.php属性)设置为sync以外的任何值。

  4. 使用--queue mail选项运行队列工作器:

    $ php artisan queue:work --queue mail
    

    您可以在多个队列上运行worker,但是只有rateLimit设置中引用的队列会受到速率限制:

    $ php artisan qeueu:work --queue mail,default
    

    default队列上的作业将不受速率限制地执行。

  5. 排队一些作业以测试速率限制:

    SomeJob::dispatch()->onQueue('mail');
    SomeJob::dispatch()->onQueue('mail');
    SomeJob::dispatch()->onQueue('mail');
    SomeJob::dispatch();
    

答案 1 :(得分:0)

假设你只有一名工人,你可以这样做:

  • 做必须做的事
  • 获得时间(以微秒计)
  • 睡眠时间为1秒减去完成时间和开始时间之间的差异
基本上是这样的:

doSomething()
$time = microtime(true);
usleep(1000 - ($time - LARAVEL_START));

答案 2 :(得分:0)

我将工作阙限制为每天最多100个工作。我选择使用'延迟'功能。

  1. 我有一个作业表的ORM类。
  2. 我在限制队列中查找最后一个作业。
  3. 增加$ last_job-> available_at 15分钟
  4. 在结束队列之前将结果传递给新作业。
  5. 职业班

    <?php
    namespace FuquIo\LaravelJobs\Orm;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Job extends Model{
        protected $dateFormat = 'U';
        protected $dates = ['reserved_at', 'available_at'];
    }
    

    没有太多背景的示例延迟......

    $que = config(ServiceProvider::SHORT_NAME . '.job-queue');
    
    
    $preceeding_job = Job::whereQueue($que['name'])
                         ->orderBy('available_at', 'DESC')
                         ->first();
    
    if(!empty($preceeding_job)){
        $available = $preceeding_job->available_at;
    }else{
        $available = Carbon::now();
    }
    
    
    ProbeGoogle::dispatch($obj)
               ->onConnection($que['connection'])
               ->onQueue($que['name'])
               ->delay($available->addMinutes(15));
    

    请注意,已完成的作业将从作业表中删除,因此您需要另一种跟踪它们的方法,并需要更多逻辑来计算$ available。我使用https://github.com/imTigger/laravel-job-status。对于这个例子,我采用了简单的逻辑。它将在队列中的最后一个作业后15分钟或从现在起15分钟后开始。这有助于解决问题,以防最后一个工作在2秒前解雇并消失。

答案 3 :(得分:0)

如果您需要“限制”并且没有将Redis用作队列驱动程序,则可以尝试使用以下代码:

public function throttledJobDispatch( $delayInSeconds = 1 ) 
{
   $lastJobDispatched = Cache::get('lastJobDispatched');

   if( !$lastJobDispatched ) {
      $delay_until = now();
   } else { 
      if ($lastJobDispatched->addSeconds($delayInSeconds) < now()) {
         $delay_until = now();
      } else {
         $delay_until = $lastJobDispatched->addSeconds($delayInSeconds);
      }
   }
   Job::dispatch()->onQueue('YourQueue')->delay($delay_until);
   Cache::put('lastJobDispatched', $delay_until, now()->addYears(1) );
}

此代码的作用是将作业释放到队列中,并将开始时间设置为最后调度的作业的开始时间之后的X秒。我用数据库作为队列驱动程序和文件作为缓存驱动程序成功地对此进行了测试。

到目前为止,我遇到了两个小问题:

1)当您仅使用1秒作为延迟时,具体取决于您的队列工作程序-队列工作程序实际上可能仅每隔几秒钟“唤醒”一次。因此,如果每3秒唤醒一次,它将一次执行3个作业,然后再次“睡眠” 3秒。但是平均,您仍然只会每秒执行一项工作。

2)在Laravel 5.7中,无法使用Carbon将作业延迟设置为小于一秒,因为它尚不支持毫秒或微秒。 Laravel 5.8应该可以实现-只需使用addMilliseconds而不是addSeconds

答案 4 :(得分:0)

spatie/laravel-rate-limited-job-middleware

如果您使用的是laravel 6或更高版本,这是一个不错的软件包。不错的是,您可以在作业中配置中间件。

安装

composer require spatie/laravel-rate-limited-job-middleware

答案 5 :(得分:-1)

您可以使用此程序包对Redis或其他来源(如文件)使用速率限制。使用设置将桶大小和速率设置为时间限制的分数,因此存储量非常小。

composer require bandwidth-throttle/token-bucket

https://github.com/bandwidth-throttle/token-bucket

它允许你将支票包裹在if中,因此它将等待一个免费令牌可用,在你的例子中每分钟1。实际上,它使服务在新的一分钟内睡眠所需的时间。