Ограничение или регулирование скорости очереди Laravel

Я работаю над приложением, которое требует получения данных со стороннего сервера, и этот сервер разрешает максимум 1 запрос в секунду.

Теперь все запросы отправляются как задание, и я пытаюсь реализовать Laravel "ограничение скорости «выпускать 1 задание в секунду, но не может понять, почему это должно быть реализовано, и в сети нет реальных примеров.

Кто-нибудь реализовал?

Есть намёк на это?


person Meathanjay    schedule 20.11.2017    source источник
comment
Сделайте свой собственный внутренний вызов API для использования внешнего API, используйте задание для использования собственного внутреннего API. Ограничьте скорость вашего собственного внутреннего API.   -  person Ohgodwhy    schedule 20.11.2017
comment
Я делаю нечто подобное прямо сейчас, и моя идея такова: когда вы отправляете задание в очередь, сохраняйте дату и время отправки в кеше. Для всех отправок проверьте кеш, чтобы узнать, когда было отправлено последнее задание, и если оно меньше 1 секунды, используйте Job::dispatch()->delay($lastDispatchDateTime->addSeconds(1));   -  person Emanuel S.    schedule 07.03.2019


Ответы (5)


Я являюсь автором пакета композитора mxl / laravel-queue-rate-limit .

Это позволяет вам оценивать ограниченные задания в определенной очереди без использования Redis.

  1. Установите его с помощью:

    $ composer require mxl/laravel-queue-rate-limit:^1.0
    
  2. Этот пакет совместим с Laravel 5.5+ и использует auto- обнаружение, чтобы добавить MichaelLedin\LaravelQueueRateLimit\QueueServiceProvider::class к поставщикам.

  3. Добавьте настройки ограничения скорости в config/queue.php:

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

    Эти настройки позволяют запускать 1 задание каждые 5 секунд в mail очереди. Убедитесь, что для драйвера очереди по умолчанию (свойство 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();
    
person mixel    schedule 02.08.2019

Предполагая, что у вас есть только один рабочий, вы можете сделать что-то вроде этого:

  • делай то, что должно быть сделано
  • получить время (в микросекундах)
  • время сна, равное 1 секунде минус разница между временем окончания и временем начала

так в основном:

doSomething()
$time = microtime(true);
usleep(1000 - ($time - LARAVEL_START));
person Marcin Nabiałek    schedule 20.11.2017

Если вам нужно "регулирование" и вы не используете 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.

person Emanuel S.    schedule 07.03.2019

spatie / laravel-rate-limited-job-middleware

Это хороший пакет, если вы используете laravel 6 или выше. Приятно то, что вы можете настраивать промежуточное ПО прямо в работе.

Установить

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

person namal    schedule 20.08.2020

Вы можете использовать этот пакет для использования ограничения скорости с Redis или другим источником, например файлом. Использует настройки для установки размера корзины и скорости в долях от лимита времени, поэтому хранилище очень мало.

composer require bandwidth-throttle/token-bucket

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

Он позволяет вам обернуть проверку в if, поэтому он будет ждать, пока будет доступен бесплатный токен, 1 минуту в вашем примере. По сути, он переводит службу в спящий режим на необходимое время до новой минуты.

person tristanbailey    schedule 25.11.2017