Laravel队列速率限制或调节

p5fdfcr1  于 2022-12-19  发布在  其他
关注(0)|答案(6)|浏览(247)

我正在开发一个需要从第三方服务器获取数据的应用程序,该服务器允许每秒最大1个请求。
现在,所有的请求都作为作业发送,我正在尝试实现Laravel的“限速”,以每秒释放1个作业,但无法弄清楚为什么要实现它,而且在网络上也没有现实生活中的例子。
有人实施了吗?
有什么线索吗?

xsuvu9jc

xsuvu9jc1#

我是mxl/laravel-queue-rate-limit Composer软件包的作者。
它允许你在不使用Redis的情况下对特定队列中的作业进行速率限制。
1.安装时:

$ composer require mxl/laravel-queue-rate-limit:^1.0

1.此软件包与Laravel 5.5+兼容,并使用auto-discovery功能将MichaelLedin\LaravelQueueRateLimit\QueueServiceProvider::class添加到提供程序。
1.将速率限制设置添加到config/queue.php

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

这些设置允许在mail队列上每5秒运行1个作业。请确保默认队列驱动程序(config/queue.php中的default属性)设置为除sync之外的任何值。
1.使用--queue mail选项运行队列工作进程:

$ php artisan queue:work --queue mail

您可以在多个队列上运行工作进程,但只有rateLimit设置中引用的队列才受速率限制:

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

default队列上的作业将在没有速率限制的情况下执行。
1.将一些作业排队以测试速率限制:

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

ncecgwcz2#

假设您只有一个工人,您可以执行以下操作:

  • 做该做的事
  • 获取时间(以微秒计)
  • 休眠时间为1秒减去结束时间和开始时间之差

所以基本上

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

4c8rllxm3#

如果你需要“节流”并且没有使用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

9fkzdhlc

9fkzdhlc4#

spatie/laravel-rate-limited-job-middleware
如果你使用的是Laravel 6或更高版本,这是一个很好的包。好的是你可以在作业中配置中间件。
安装
第一个月

dzhpxtsq

dzhpxtsq5#

我最近也遇到了同样的问题,Laravel的开箱即用的作业速率限制器不允许你设置每秒的执行限制。
我通过编写一个定制的作业中间件来处理它,如下所示:

<?php

namespace App\Jobs\Middleware;

use Illuminate\Support\Facades\Redis;

class RedisRateLimited
{
    /**
     * Uses Redis to throttle the execution of a job.
     *
     * @param int $allow count of jobs you wish to allow to execute
     * @param int $every period of time in seconds
     */
    public function __construct(protected int $allow, protected int $every)
    {}

    /**
     * Process the queued job.
     *
     * @param  mixed  $job
     * @param  callable  $next
     * @return mixed
     */
    public function handle($job, $next)
    {
        Redis::throttle('your-key-here')
            ->block(0)->allow($this->allow)->every($this->every)
            ->then(function () use ($job, $next) {
                // Lock obtained...
                $next($job);
            }, function () use ($job) {
                // Could not obtain lock...
                $job->release(5);
            });
    }
}

然后将其附加到相关作业,如下所示:

/**
 * Get the middleware the job should pass through.
 *
 * @return array
 */
public function middleware()
{
    return [new RedisRateLimited(allow: 1, every: 1)];
}
jei2mxaa

jei2mxaa6#

你可以用这个包来限制Redis或其他资源的速率,比如文件。使用设置来设置桶的大小和速率作为时间限制的分数,所以存储空间非常小。

composer require bandwidth-throttle/token-bucket

https://github.com/bandwidth-throttle/token-bucket
它允许你用if来 Package 检查,所以它会等待一个免费的令牌可用,在你的例子中是每分钟1个,实际上,它使服务休眠所需的时间,直到一个新的分钟。

相关问题