我正在开发一个需要从第三方服务器获取数据的应用程序,并且该服务器每秒最多允许 1 个请求。
现在,所有请求都作为作业发送,我正在尝试实施 Laravel“速率限制”以每秒释放 1 个作业,但无法弄清楚为什么应该实施它,并且网络中没有真实的例子。
有人实施吗?
这有什么暗示吗?
我正在开发一个需要从第三方服务器获取数据的应用程序,并且该服务器每秒最多允许 1 个请求。
现在,所有请求都作为作业发送,我正在尝试实施 Laravel“速率限制”以每秒释放 1 个作业,但无法弄清楚为什么应该实施它,并且网络中没有真实的例子。
有人实施吗?
这有什么暗示吗?
我是mxl/laravel-queue-rate-limit Composer 包的作者。
它允许您在不使用 Redis 的情况下对特定队列上的限制作业进行评级。
安装它:
$ composer require mxl/laravel-queue-rate-limit:^1.0
该软件包与 Laravel 5.5+ 兼容,并使用自动发现功能添加MichaelLedin\LaravelQueueRateLimit\QueueServiceProvider::class
到提供程序。
将速率限制设置添加到config/queue.php
:
'rateLimit' => [
'mail' => [
'allows' => 1,
'every' => 5
]
]
这些设置允许在mail
队列中每 5 秒运行 1 个作业。确保将默认队列驱动程序(default
中的属性config/queue.php
)设置为除 之外的任何值sync
。
使用以下选项运行队列工作者--queue mail
:
$ php artisan queue:work --queue mail
您可以在多个队列上运行 worker,但只有在rateLimit
设置中引用的队列才会受到速率限制:
$ php artisan qeueu:work --queue mail,default
队列中的作业default
将在没有速率限制的情况下执行。
排队一些作业以测试速率限制:
SomeJob::dispatch()->onQueue('mail');
SomeJob::dispatch()->onQueue('mail');
SomeJob::dispatch()->onQueue('mail');
SomeJob::dispatch();
spatie/laravel-rate-limited-job-middleware
如果您使用的是 laravel 6 或更高版本,这是一个不错的软件包。好的是你可以在工作中配置中间件。
安装
composer require spatie/laravel-rate-limited-job-middleware
如果您需要“节流”并且不使用 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
.
假设你只有一个工人,你可以做这样的事情:
所以基本上:
doSomething()
$time = microtime(true);
usleep(1000 - ($time - LARAVEL_START));
您可以使用此包对 Redis 或其他源(如文件)使用速率限制。使用设置将存储桶大小和速率设置为时间限制的分数,因此存储空间非常小。
composer require bandwidth-throttle/token-bucket
https://github.com/bandwidth-throttle/token-bucket
它允许您将检查包装在 if 中,因此它将等待免费令牌可用,在您的示例中每分钟 1 个。实际上,它使服务休眠所需的时间,直到新的一分钟。