Redis дросселирует задание Laravel, которое выполнялось слишком много раз или выполнялось слишком долго

Я хочу отправить sms с помощью nexmo, используя Laravel Queue с Redis, но некоторые задания терпят неудачу, и я не могу понять, почему. В моей локальной среде я отправляю 1 sms каждые 10 секунд, так что вот метод обработки моей работы:

public function handle()
    { 
        Redis::throttle('throttle:sms')->allow(1)->every(10)->then(function(){
            Log::info($this->notifId." start : ".date('H:m:s'));
            try{
                $before = microtime(true);
                $response = Nexmo::message()->send([
                                'to'   => $this->to,
                                'from' => '16105552344',
                                'text' => $this->message
                            ]);
                $notif = NotificationHistory::find($this->notifId);
                $notif->nexmo_message_id=$response->getMessageId();
                $notif->save();

                $after = microtime(true);
                Log::info(($after-$before)." sec\n");
            }catch(Exeption $e){
                log::warning($e);
            }
        },function($error){
            Log::error($error);
            return $this->release(10);//release job in X second
        });
    }

Но я получаю Illuminate\Contracts\Redis\LimiterTimeoutException и наконец MaxAttemptsExceededException, когда достигаю лимита попыток.

Я начинаю свой рабочий с php artisan queue:work --queue=sms --timeout=60 и распределяю свою работу следующим образом:

foreach($someEntities as $entitiy) {
            $notif = new NotificationHistory();
            $notif->notifiable()->associate($entity);
            $notif->message=$entity->message;
            $notif->status=NotificationHistory::$statusList[-1];
            $notif->save();
            dispatch(new SendSMS($entity->message."_".$notif->id,$entity->phone,$notif->id))->onConnection('redis')->onQueue('sms');
    }

При попытке отправить 8 смс первые 5 или 6 работают, но для остальных я получаю исключение.

ИЗМЕНИТЬ Я получаю те же ошибки без nexmo:

public function handle()
    { 
        Redis::throttle('throttle:sms')->allow(1)->every(10)->then(function(){
            Log::info($this->notifId." startAt : ".date('H:m:s'));
        },function($error){
            Log::error($error);
            return $this->release(10);//release job in X second
        });
    }

person Alexis    schedule 30.07.2020    source источник
comment
Можете ли вы понять, почему отдельная работа терпит неудачу? API регулирует скорость 30 вызовов в секунду (хотя операторы связи устанавливают свои собственные ограничения, поэтому внутреннее регулирование может произойти после того, как мы примем сообщение). SDK будет пытаться самостоятельно регулировать скорость, но обычно это произойдет только в том случае, если вы выполняете более 30 вызовов API в секунду.   -  person dragonmantank    schedule 30.07.2020
comment
@dragonmantank На данный момент я перенаправляю запросы на поддельную конечную точку, чтобы не было дросселирования API. Индивидуальные запросы терпят неудачу несколько раз из-за LimiterTimeoutException, когда они терпят неудачу слишком много раз, это бросается MaxAttemptsExceededException.   -  person Alexis    schedule 30.07.2020


Ответы (1)


Проблема заключалась в файле горизонта, из-за которого попытки были 3.

На самом деле работник очереди запускается не только один раз каждые 10 секунд, он запускается непрерывно, если в очереди что-то есть. Когда он обрабатывает задание, если он уже обрабатывал задание за последние 10 секунд, он удалит его текущее задание из очереди и вернет его через X секунд (определено в release(x)), сгенерирует LimiterTimeoutException и увеличит его значение попыток. Поэтому, когда работник достигнет 3-х попыток выполнения одной и той же работы, он потерпит неудачу.

person Alexis    schedule 11.08.2020