Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Laravel Artisan Queue Ensurer - Set a cron job to run this file periodically to ensure that Laravel's queue is processing all the time. If the queue listener stopped, restart it!
<?php
function runCommand ()
{
$command = 'php artisan queue:listen > /dev/null & echo $!';
$number = exec($command);
file_put_contents(__DIR__ . '/queue.pid', $number);
}
if (file_exists(__DIR__ . '/queue.pid')) {
$pid = file_get_contents(__DIR__ . '/queue.pid');
$result = exec('ps | grep ' . $pid);
if ($result == '') {
runCommand();
}
} else {
runCommand();
}
@mauris

This comment has been minimized.

Copy link
Owner Author

mauris commented Apr 28, 2014

Set a cron job to run this file periodically to ensure that Laravel's queue is processing all the time. If the queue listener stopped, restart it!

@eridal

This comment has been minimized.

Copy link

eridal commented Apr 28, 2014

ps $pid will work better

@NDuggan

This comment has been minimized.

Copy link

NDuggan commented May 21, 2015

I know this is old, but is this used instead of something likes Supervisor?

@morganstar

This comment has been minimized.

Copy link

morganstar commented Oct 19, 2015

I've adapted this code just slightly and have it running through the Laravel 5.0 scheduling system. I set a cron job to run the artisan schedule:run command every minute per the docs. Inside of app/Console/Kernel.php I put the following in the "schedule" function.:

protected function schedule(Schedule $schedule)
{
    $schedule->call(function() {
        // check that the queue listener is running and restart it if it isn't
        $run_command = false;
        if (file_exists(__DIR__ . '/queue.pid')) {
            $pid = file_get_contents(__DIR__ . '/queue.pid');
            $result = exec("ps -p $pid --no-heading | awk '{print $1}'");
            if ($result == '') {
                $run_command = true;
            }
        } else {
            $run_command = true;
        }
        if($run_command)
        {
            $command = '/usr/local/bin/php /home/user/webapp/artisan queue:listen > /dev/null & echo $!';
            $number = exec($command);
            file_put_contents(__DIR__ . '/queue.pid', $number);
        }
    })->name('monitor_queue_listener')->everyFiveMinutes();
}
@ElliottLandsborough

This comment has been minimized.

Copy link

ElliottLandsborough commented Nov 4, 2015

I tried to get it to work with the symphony process class but got stuck because symphony kills the process when php stops. Have pasted anyway in case anyone would like to see.

use Symfony\Component\Process\Process;
//use Symfony\Component\Process\Exception\ProcessFailedException;

    protected function schedule(Schedule $schedule)
    {
        $schedule->call(function() {
            $pidfile = base_path() . DIRECTORY_SEPARATOR . 'queue.pid';
            $run_command = false;
            if (file_exists($pidfile)) {
                $pid = file_get_contents($pidfile);
                $command = "ps -p $pid --no-heading | awk '{print $1}'";
                $process = new Process($command);
                $process->run();
                if ($process->isSuccessful()) {
                    if ($process->getOutput() == '') {
                        $run_command = true;
                    }
                }
            } else {
                $run_command = true;
            }
            if($run_command)
            {
                $phpBin = $_SERVER['_'];
                $artisan = base_path() . DIRECTORY_SEPARATOR . 'artisan';
                /* does not work - when php ends, the command ends
                $command = $phpBin . ' ' . $artisan . ' queue:listen';
                $process = new Process($command);
                $process->start();
                file_put_contents($pidfile, $process->getPid());
                */
                // so let's settle for exec
                $command = $phpBin . ' ' . $artisan . ' queue:listen > /dev/null & echo $!';
                $number = exec($command);
                file_put_contents($pidfile, $number);   
            }
        })->name('monitor_queue_listener')->everyFiveMinutes();
    }
@xxzefgh

This comment has been minimized.

Copy link

xxzefgh commented Apr 26, 2016

Confirmed working on 5.2

<?php

function runCommand ()
{
    $command = 'php ' . __DIR__ . '/artisan queue:listen > /dev/null & echo $!';
    $number = exec($command);
    file_put_contents(__DIR__ . '/queue.pid', $number);
}

if (file_exists(__DIR__ . '/queue.pid')) {
    $pid = file_get_contents(__DIR__ . '/queue.pid');
    $result = exec('ps -e | grep ' . $pid);
    if ($result == '') {
        runCommand();
    }
} else {
    runCommand();
}
@xxzefgh

This comment has been minimized.

Copy link

xxzefgh commented Apr 26, 2016

Also if anyone wants to check if artisan is running with ajax

Route::get('queue_status', function() {
    $output = function ($success) {
        return response()->json(['running' => $success]);
    };

    $pidFile = base_path() . '/queue.pid';
    if (file_exists($pidFile)) {
        $pid = file_get_contents($pidFile);
        $result = exec('ps -e | grep ' . $pid);
        if ($result == '') {
            return $output(false);
        } else {
            return $output(true);
        }
    } else {
        return $output(false);
    }
});
@mohamedsharaf

This comment has been minimized.

Copy link

mohamedsharaf commented May 4, 2016

 $schedule->call(
            function(){
                // you can pass queue name instead of default
                Artisan::call('queue:listen', array('--queue' => 'default'));
            }
        )->name('ensurequeueisrunning')->withoutOverlapping()->everyMinute();
@di5abled

This comment has been minimized.

Copy link

di5abled commented Jul 5, 2016

Improved the code a little bit and it seems to work fine for me in my current L 5.2:

$schedule->call(function() {
    $run_command = false;
    $monitor_file_path = storage_path('queue.pid');

    if (file_exists($monitor_file_path)) {
        $pid = file_get_contents($monitor_file_path);
        $result = exec("ps -p $pid --no-heading | awk '{print $1}'");

        if ($result == '') {
            $run_command = true;
        }
    } else {
        $run_command = true;
    }

    if($run_command)
    {
        $command = 'php '. base_path('artisan'). ' queue:listen > /dev/null & echo $!';
        $number = exec($command);
        file_put_contents($monitor_file_path, $number);
    }
})
->name('monitor_queue_listener')
->everyFiveMinutes();
@ghost

This comment has been minimized.

Copy link

ghost commented Jul 14, 2016

@di5abled how this function will be called?

@ghost

This comment has been minimized.

Copy link

ghost commented Jul 14, 2016

or i just have to enqueue my cron jobs and it will run automatically?

@ratatatKE

This comment has been minimized.

Copy link

ratatatKE commented Oct 31, 2016

Do you have an adaptation of the queue ensurer that will work on a windows server that does not have grep installed?

@peyman1992

This comment has been minimized.

Copy link

peyman1992 commented Dec 10, 2016

if exec function is disable you can use this code

        $schedule->call(function () {
            $descriptorspec = array(
                0 => array("pipe", "r"),
                1 => array("pipe", "w"),
            );
            $runCommand = false;
            $queueFile = storage_path('queue.pid');
            if (file_exists($queueFile)) {
                $pid = intval(file_get_contents($queueFile));
                $process = proc_open("ps -p $pid --no-heading | awk '{print $1}'", $descriptorspec, $pipes);
                $result = '';
                if (is_resource($process)) {
                    $result = stream_get_contents($pipes[1]);
                    fclose($pipes[1]);
                }

                if ($result == '') {
                    $runCommand = true;
                }
            } else {
                $runCommand = true;
            }
            if ($runCommand) {
                $dir = base_path() . DIRECTORY_SEPARATOR;
                $command = "php {$dir}artisan queue:listen --timeout=60 --tries=1 > '/dev/null' 2>&1 & echo $!";
                $process = proc_open("$command", $descriptorspec, $pipes, null, ["register_argc_argv" => "on"]);
                $number = '';
                if (is_resource($process)) {
                    $number = stream_get_contents($pipes[1]);
                    fclose($pipes[1]);
                }
                file_put_contents($queueFile, $number);
            }
        });
@weotch

This comment has been minimized.

Copy link

weotch commented Feb 22, 2017

This sounds like a good solution:

// Using `queue:work` for Laravel 5.4
$schedule->command('queue:work')->everyMinute()->withoutOverlapping();

Anyone see any issue with it?


Nvm, it doesn't background the queue:work like this snippet does.

@kohlerdominik

This comment has been minimized.

Copy link

kohlerdominik commented Aug 24, 2017

A made a simple solution for this (Laravel 5.5 dev).

I created a new function, that checks if the process is running.
Then, a simple if-condition arround the command does the thing

        // start the queue daemon, if its not running
        if ( !$this->osProcessIsRunning('queue:work') ) {
            $schedule->command('queue:work')  ->everyMinute();
        }

I put the new function right in app/Console/Commands/Kernel.php:

    /**
     * checks, if a process with $needle in the name is running
     *
     * @param string $needle
     * @return bool
     */
    protected function osProcessIsRunning($needle)
    {   
        // get process status. the "-ww"-option is important to get the full output!
        exec('ps aux -ww', $process_status);

        
        // search $needle in process status
        $result = array_filter($process_status,
            function($var) use ($needle)
            {   return strpos($var, $needle); });


        // if the result is not empty, the needle exists in running processes
        if (!empty($result)) {
            
            return true;
        }

        return false;
    }

Edit: Execution time on my dev-machine is 3-4ms.

@developmentvk

This comment has been minimized.

Copy link

developmentvk commented Feb 18, 2018

Thanks kohlerdominik!,
It's working perfectly.

@maurodaprotis

This comment has been minimized.

Copy link

maurodaprotis commented Mar 16, 2018

@kohlerdominik solution work's great! Thanks!

@henryonsoftware

This comment has been minimized.

Copy link

henryonsoftware commented May 12, 2018

@kohlerdominik perfect solution. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.