Search code examples
laravelqueuebatch-processingjobs

Is it possible to make a job batch in Laravel to wait until a certain time in the future before running the next job?


I have a command where a job batch that runs some work that lasts at least 40 minutes is created, but I need the batch to pause about 10 hours if the next job is going to be executed after, let's say 2a.m., and start again at 12p.m. I did a schedule for the commando to not create a new batch if the time is between that hours, the problem now is that I need to pause the batch if the clock hits the interval. I was thinking to make a do while at the beggining of each job that checks the time of the day and keeps looping if the time is in that interval, but I'm not sure if the supervisor or the queue worker will hang that long waiting for job to end. Technically it's like is working on something but it's a big amount of time.


Solution

  • Yes, it was possible to loop until certain time in the future just comparing date('Hi') to the time in string (eg if(date('Hi') <= '0800') ... ) and keeping the max_execution_time = 0 in php.ini and the retry_after in database driver on queue.php to 58000 (more than the longest time a job could take). I kept running the job batch almost 16 hours and it restarted normally, the thing is, my server admin told me that changing php.ini wasn't an option, so I will search for anything else and let you know if there's other way to keep a job batch waiting that long.

    UPDATE: Using Illuminate\Support\Facades\Queue::looping inside the EventServiceProvider works better, and we don't need to change neither php.ini nor supervisor stopwaitsecs to match the waiting time, even queue.php retry_after can be set only to the time the job will take. Keeping it short, using a flag that let us know if it's waiting time as told on this other answer, I did a command for creating a database cache with an expiration time of several hours that "looping" will check, so if it haven't expired, "looping" will be returning false keeping the worker from taking a new job. EventServiceProvider boot method look something like this.

    public function boot()
    {
        parent::boot();
    
        Queue::looping(function (\Illuminate\Queue\Events\Looping $event) {
            if (($event->queue == 'queuename') && (Cache::get('waitqueue'))) {
                return false;
            }
        });
    

    }