I want so send sms with nexmo using Laravel Queue with Redis but some jobs fail and I can't understand why. In my local environment, I send 1 sms every 10s so here is the handle method of my job :
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
});
}
But I get some Illuminate\Contracts\Redis\LimiterTimeoutException
and finaly MaxAttemptsExceededException
when I reach the tries limit.
I start my worker with php artisan queue:work --queue=sms --timeout=60
And I dispatch my job like this :
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');
}
When trying to send 8 sms, the firsts 5 or 6 works but I get an exception for the others.
EDIT I get the same errors withtout 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
});
}
The problem was the "horizon" file which forced the tries to 3.
The queue worker doesn't in fact only run one time every 10s, it run continuously if there is something in the queue.
When it process a job, if it already have process a job in the last 10s it will remove it's current job from the queue and put it back in X seconds (defined in release(x)
), generate a LimiterTimeoutException
and increase it's tries value.
So when the worker reach 3 tries on the same job, it will fail.