Я использую Laravel Horizon и Redis, и я пытаюсь ограничить его. Я использую внешний API с ограничением скорости 100 запросов в минуту. Мне нужно сделать около 700 запросов. У меня он настроен так, что каждое задание, которое я добавляю в очередь, выполняет только один вызов API в самом задании. Так что, если я задушу очередь, я смогу оставаться в рамках. По какой-то причине дросселирования не происходит, и вместо этого происходит продувка очереди (что, конечно, вызывает множество ошибок API). Однако дроссель работает локально, но не на моем сервере.
Изначально я пытался задросселировать документацию очереди Laravel, но смог заставить ее работать только локально, поэтому я переключился на опробование laravel-queue-rate-limit на Github. В соответствии с README я добавил в свой queue.php
файл конфигурации следующее:
'rateLimits' => [
'default' => [ // queue name
'allows' => 75, // 75 job
'every' => 60 // per 60 seconds
]
],
По какой-то причине регулирование работает правильно, когда я запускаю его в своей локальной среде Ubuntu, но он не работает на моем сервере (также в Ubuntu). На сервере он просто продувает очередь, как будто дроссельной заслонки нет.
Есть ли что-то, что я делаю неправильно, или, может быть, лучший способ справиться с внешним API с ограничением скорости?
Изменить 1:
config / horizon.php
'environments' => [
'production' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'simple',
'processes' => 3,
'tries' => 100,
],
],
Одна из ручек, с которой начинается большинство работ:
public function handle()
{
$updatedPlayerIds = [];
foreach ($this->players as $player) {
$playerUpdate = Player::updateOrCreate(
[
'id' => $player['id'],
],
[
'faction_id' => $player['faction_id'],
'name' => $player['name'],
]
);
// Storing id's of records updated
$updatedPlayerIds[] = $playerUpdate->id;
// If it's a new player or the player was last updated awhile ago, then get new data!
if ($playerUpdate->wasRecentlyCreated ||
$playerUpdate->last_complete_update_at == null ||
Carbon::parse($playerUpdate->last_complete_update_at)->diffInHours(Carbon::now()) >= 6) {
Log::info("Updating '{$playerUpdate->name}' with new data", ['playerUpdate' => $playerUpdate]);
UpdatePlayer::dispatch($playerUpdate);
} else {
// Log::debug("Player data fresh, no update performed", ['playerUpdate' => $playerUpdate]);
}
}
//Delete any ID's that were not updated via the API
Player::where('faction_id', $this->faction->id)->whereNotIn('id', $updatedPlayerIds)->delete();
}
Кроме того, вот приблизительная диаграмма, которую я сделал, пытаясь проиллюстрировать, как у меня есть несколько файлов PHP заданий, которые в конечном итоге создаются за короткий промежуток времени, особенно такие, как updatePlayer()
, которые часто создаются 700 раз.
default
-block => 60
? Возможно, это проблема тайм-аута, когда тайм-аут срабатывает через 3 секунды и сразу же вызывается другой обратный вызов. - person Qumber   schedule 30.06.2020Redis::throttle('key' )
-->block(60)
. - person Qumber   schedule 30.06.2020Redis::throttle('torn-api')->allow(75)->every(60)->block(60)
. Я пытаюсь разрешить выполнение только 75 заданий за 60 секунд. - person ComputerLocus   schedule 01.07.2020php artisan queue:work
, а не через superviserd worker, я получаю ошибкуIlluminate\Queue\MaxAttemptsExceededException: App\Jobs\UpdatePlayer has been attempted too many times or run too long. The job may have previously timed out. in
. И я увижу кучу попыток на них вроде 20 попыток. - person ComputerLocus   schedule 01.07.2020(config/horizon.php)
? Возможно, сделайте это и зарегистрируйте любое исключение, используя методfailed
в самом задании; вот так - stackoverflow.com/a/53172981/10625611 - person Qumber   schedule 01.07.2020php artisan queue:work
, кажется намного более надежным, чем метод супервизора. Я рассматриваю просто фоновый процесс очереди вместо супервизора, поскольку он кажется слишком непоследовательным. Также я отредактировал некоторые дополнительные детали в OP - person ComputerLocus   schedule 03.07.2020retry_after
иtimeout
в конфигурации Horizon. Вашеretry_after
значение в конфигурации всегда должно быть больше, чем время, необходимое для выполнения работы. И значениеtimeout
должно быть на несколько секунд короче, чем значениеretry_after
. См. Эту проблему и этот пункт в doc - person Qumber   schedule 03.07.2020retry_after
установлен на 70 В Horizon.phpwaits.redis:default
изменен на 65, аtimeout
изменен на 60 (в разделе сред). Я также удалил различные флаги, которые у меня были на слушателях очереди супервизора, чтобы использовались только значения конфигурации. Также в моем промежуточном программном обеспеченииRateLimited
я добавил->block(60)
, как вы упомянули. И я вернулся к обычному троттлингу вместо использования пакета. - person ComputerLocus   schedule 05.07.2020