Search code examples
laravelredislaravel-5.5throttling

Laravel Jobs fail on Redis when attempting to use throttle


End Goal

The aim is for my application to fire off potentially a lot of emails to the Redis queue (This bit is working) and then Redis throttle the processing of these to only a set number of emails every selected number of minutes.

For this example, I have a test job that appends the time to a file and I am attempting to throttle it to once every 60 seconds.

The story so far....

So far, I have the application successfully pushing a test amount of 50 jobs to the Redis queue. I can log in to Horizon and see these 50 jobs in the "processjob" queue. I can also log in to redis-cli and see 50 sets under the list key "queues:processjob".

My issue is that as soon as I attempt to put the throttle on, only 1 job runs and the rest fail with the following error:

Predis\Response\ServerException: ERR Error running script (call to f_29cc07bd431ccbf64637e5dcb60484560fdfa2da): @user_script:10: WRONGTYPE Operation against a key holding the wrong kind of value in /var/www/html/smhub/vendor/predis/predis/src/Client.php:370

If I remove the throttle, all works file and 5 jobs are instantly ran.

I thought maybe it was the incorrect key name but if I change the following:

    public function handle()
{
    //
    Redis::throttle('queues:processjob')->allow(1)->every(60)->then(function(){

      Storage::disk('local')->append('testFile.txt',date("Y-m-d H:i:s"));
    }, function (){
      return $this->release(10);
    });
}

to this:

    public function handle()
{
    //
    Redis::funnel('queues:processjob')->limit(1)->then(function(){

      Storage::disk('local')->append('testFile.txt',date("Y-m-d H:i:s"));
    }, function (){
      return $this->release(10);
    });
}

then it all works fine.

My thoughts...

Something tells me that the issue is that the redis key is of type "list" and that the jobs are all under a single list. That being said, if it didn't work this way, how would we throttle a queue as the throttle requires a unique key.


Solution

  • For anybody else that is having issues attempting to get this to work and is getting the same issue as I was, this is what resolved my issues:

    The Fault

    I assumed that Redis::throttle('queues:processjob') was meant to be referring to the queue that you wanted to be throttled. However, after some re-reading of the documentation and testing of the code, I realized that this was not the case.

    The Fix

    Redis::throttle('queues:processjob') is meant to point to it's own 'holding' queue and so must be a unique Redis key name. Therefore, changing it to Redis::throttle('throttle:queues:processjob') worked fine for me.

    The workings

    When I first looked in to this, I assumed that that Redis::throttle('this') throttled the queue that you specified. To some degree this is correct but it will not work if the job was created via another means.

    Redis::throttle('this') actually creates a new 'holding' queue where the jobs go until the condition(s) you specify are met. So jobs will go to the queue 'this' in this example and when the throttle trigger is released, they will be passed to the queue specified in their execution code. In this case, 'queues:processjob'.

    I hope this helps!