Alexis
Alexis

Reputation: 411

Laravel Queue - Prevent job retry on certain condition

I call an API to send SMS and save it's response using Redis::throttle to limit the rate of the call to 5 calls every 60s with :

Redis::throttle('throttle:sms')->allow(5)->every(60)->then(function(){
    //->API call
    //->Save response
},function($error){//could not obtain lock
    return $this->release(60);//Put back in queue in 60s
});

I didn't specify any $tries because if the lock cannot be obtain, it count as a try and if I process a long queue and the lock cannot be obtain many time the job will fail without any "real" errors. But I dont want the job to be processed forever, if there is a real error (like if the response cannot be saved) it should fail without retry especially if the error appends after the API call as a retry will send another SMS (which I definitely don't want).

What I've tried :

Redis::throttle('throttle')->allow(5)->every(60)->then(function(){
    try{
        $response = MyAPICall();
        $test = 8/0;
        saveResponse($response);
    } catch(\LimiterTimeoutException $e){
        throw $e;
    } catch(Exception $e){
        Log::error($e);
        $this->fail($exception = null);
        //$this->delete();
    }
},function($error){//could not obtain lock
    Log::info($error);
    return $this->release(60);//Put back in queue in 60s
});

If there is an exception because the lock cannot be obtain, I throw it back to let the queue handle it but if it's another exception, I log the error and fail or delete the job. But it's not working with either delete() or fail(), the job is always retried.

How can I remove the job if there is an exception other than the LimiterTimeoutException ?

Upvotes: 1

Views: 4737

Answers (1)

Alexis
Alexis

Reputation: 411

I was missing a "\" before Exception in my catch. Here is the fix code :

Redis::throttle('throttle:sms')->allow(5)->every(60)->then(function(){
    $response = myAPICall();
    try{
        $test = 8/0;
        SaveResponse($response);
    }
    catch (LimiterTimeoutException $exception){
        throw $exception;//throw back exception to let redis handle it below
    }
    catch (\Exception $exception) {
        Log::error($exception);
        $this->fail($exception);
    }
},function($error){//could not obtain lock
    return $this->release(60);//Put back in queue in 60s
});

I added $this->fail($exception) to make the job to show up as "failed" in Horizon.

Upvotes: 1

Related Questions