Search code examples
phplaravel-5interruptjobs

How to interrupt a PHP loop?


I have a Laravel 5.2 job that I generally want running non-stop. For illustration, let's say it generates some random number and then broadcasts it through an event to the front-end.

/**
 * Execute the job. Generate a random number.
 */
public function handle()
{
    $number = rand();
    event(new NumberWasGenerated($number)); 
}

For whatever reason, I want this job to run indefinitely. So, I made another job which loops and keeps dispatching new GenerateNumberjobs.

/**
 * Execute the job. Continuously generate numbers.
 *
 * @return void
 */
public function handle()
{
    while (true) {
        $this->dispatch(new GenerateNumber());
    }
}

I do however want to be able to "turn off" the generator should I decide to. This is where I am having trouble.

Ideally I would like to be able to hit a route like /abortwhich would then send an interrupt to my generator loop and halt its execution. How can I do this?

Alternatively, I could try a polling approach. I tried to use something like:

/**
 * Execute the job. Continuously generate numbers.
 *
 * @return void
 */
public function handle()
{
    Config::set('shouldGenerate', true);

    while (Config::get('shouldGenerate')) {
        $this->dispatch(new GenerateNumber());
    }
}

Then, in my controller method for /abort I have

public function abort()
{
    Config::set('shouldGenerate', false);
}

However, the abort doesn't seem to be working. I think the problem seems to be that the abort method never gets a chance to execute because the generator loop is being a ball hog, but I am not sure why that would be the case.

Question:

1) Can I achieve this using an interrupt approach?
2) If not, how can I achieve this through polling?


Solution

  • You can achieve this by combination of both options

    • Interrupt
    • Polling

    You can rewrite your abort action as follow

    public function abort()
    {
        Config::set('shouldGenerate', false);
        exec('PATH/TO/YOUR/RDIS/SERVER/src/redis-cli FLUSHDB');    
    }
    

    And change the handle method as follow:

    /**
     * Execute the job. Continuously generate numbers.
     *
     * @return void
     */
    public function handle()
    {
        $shouldGenerate = Config::get('shouldGenerate');
        while ($shouldGenerate) {
            $this->dispatch(new GenerateNumber());
        }
    }
    

    You can read more about the FLUSHDB of Redis server HERE Delete all the keys of the currently selected DB. This command never fails

    I hope this will work for you. Make sure your operating system user must have permission to execute the shell commands via script.