我正在处理一个需要从第三方服务器获取数据的应用程序,该服务器每秒允许最多1个请求。
现在,所有请求都作为工作发送,我正在尝试实施Laravel" Rate Limiting"每秒释放1个工作,但无法弄清楚为什么要实施它,网上没有真实的例子。
有没有人实现它?
有任何暗示吗?
答案 0 :(得分:1)
我是mxl/laravel-queue-rate-limit Composer软件包的作者。
它允许您在不使用Redis的情况下为特定队列上的作业限制率。
通过以下方式安装:
$ composer require mxl/laravel-queue-rate-limit:^1.0
此软件包与Laravel 5.5+兼容,并使用auto-discovery功能将MichaelLedin\LaravelQueueRateLimit\QueueServiceProvider::class
添加到提供程序。
将速率限制设置添加到config/queue.php
:
'rateLimit' => [
'mail' => [
'allows' => 1,
'every' => 5
]
]
这些设置允许每5秒在mail
队列上运行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();
答案 1 :(得分:0)
假设你只有一名工人,你可以这样做:
doSomething()
$time = microtime(true);
usleep(1000 - ($time - LARAVEL_START));
答案 2 :(得分:0)
我将工作阙限制为每天最多100个工作。我选择使用'延迟'功能。
职业班
<?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。实际上,它使服务在新的一分钟内睡眠所需的时间。