Using php-resque with Laravel

Jessie O’Brien wrote a great blog post explaining how he’d got php-resque setup with Laravel. I won’t rehash the background on php-resque or Laravel but instead I wanted to post because I did the exact same thing last week, but I went about it in a different way.

To begin, I ported the core of the php-resque run script (Resque.php) into an artisan task. This allows to run artisan which gives you the full laravel environment, but still run the php-resque workers. So to run the queue, it’s as simple as running

php artisan resque <queue> <logLevel> <interval> <pidFile> 
/**
 * A Laravel Task which runs the PHP-Resque worker
 * This should be run using Artisan (php artisan resque) which will 
 * then kick off a php-resque worker and listen for incoming messages 
 * coming into the redis queues.
 */
class Resque_Task
{
    /**
     * @param $arguments
     */
    public function run($arguments)
    {
        Bundle::start('php-resque');

        $queue    = array_get($arguments, 0, 'default');
        $logLevel = array_get($arguments, 1, 0);
        $interval = array_get($arguments, 2, 5);
        $pidFile  = array_get($arguments, 3);

        $redis_config = Config::get("database.redis.default");
        $backend      = $redis_config['host'] . ':' . $redis_config['port'];

        // Connect to Redis
        Resque::setBackend($backend);

        $queues           = explode(',', $queue);
        $worker           = new Resque_Worker($queues);
        $worker->logLevel = $logLevel;

        if ($pidFile) {
            file_put_contents($pidFile, getmypid()) or 
              die('Could not write PID information to ' . $pidFile);
        }

        fwrite(STDOUT, '*** Starting worker ' . $worker . "\n");

        $worker->work($interval);
    }
}

The next piece I wanted, was to be able to write each of the tasks which I execute on the queue as simple artisan tasks. That way I could test them in isolation and run them independantly of the queue just using artisan.

All I needed to do was create a simple php-resque Job which could run any artisan Task.

/**
 * A PHP-Resque Job which starts a Laravel Task.
 * This enables us to use PHP-Resque as robust processing queue
 * but still use Laravel Commands, bundles etc to do the work
 *
 */
class Laravel_Job
{
    public function setUp()
    {
    }

    public function perform()
    {
        $task      = array_get($this->args, 'task');
        $arguments = array_get($this->args, 'arguments');

        Command::run(array($task, $arguments));
    }

    public function tearDown()
    {
    }
}

So, that’s it. If I wanted to run a long-running artisan task, I can simply issue the following command (perhaps from one of my controllers in response to a user action).

Resque::enqueue('queue', 'Laravel_Job', array('task => 'LongRunningLaravelTask', 'arguments' => 'some param'), true);
05
Dec 2012
POSTED BY
POSTED IN Laravel PHP
DISCUSSION 7 Comments
  • Pelle Svensson

    I’m new to laravel and found that I was in need of Resque. Could you by anychane explain in little more detail which files you modified or added?

    • Hi Pelle

      To begin with I took the php-resque package and created a Laravel bundle for it, but if you read Jessie’s article linked above you will see he used the Composer package directly which is probably a better option.

      Once you have that done, you just need to use the code posted above to create an artisan task. If you are unfamiliar with this I would recommend reading the laravel documentation about Tasks/Commands http://laravel.com/docs/artisan/tasks#creating-tasks

      Hope that helps

      James

      • I was a bit confused as well as Pelle. I created a folder, application/workers, and placed laravel_job.php inside which contained the Laravel_Job class. I had to add: use LaravelCLICommand; in order for it to use Laravel’s Command class. Perhaps I’m not autoloading correctly? I then modified the resque task class (application/tasks/resque.php) to: require_once path(‘app’).’workers/laravel_job.php’;. Can you advise if I’m missing something or if what I did is correct? Thanks!

        • Hi Austin,

          I put both the Resque_Task and Laravel_Job classes in the application/tasks folder since that’s where artisan tasks should be located, but you are correct that you will need to put “use LaravelCLICommand;” at the top of your classes to resolve the Command class.

          After that you should just be able to create Artisan Tasks in your application/tasks folder and they will be callable from your Resque queue, e.g.

          Resque::enqueue(‘queue’, ‘Laravel_Job’, array(‘task => ‘LongRunningLaravelTask’, ‘arguments’ => ‘some param’), true);

          Thanks

  • Used your tutorial in combination with Jesse O’Brien’s. Thanks for the info!

  • I’ve been using your technique to get php-resque working on a Laravel 3 project. To start my workers, I do as you suggest:

    php artisan resque [queue] [logLevel] [interval] [pidFile]

    I’m wondering how you handle daemonizing the process for a production server. I’m looking at Monit, which may fit the bill, but the issues I see are:

    – starting the resque task as the same user as your webserver, so that logs and other files are read/writeable by both the web app and resque jobs
    – gracefully stopping and restarting the workers when I redeploy my app (currently using Capistrano)

    What do you do?

  • kartik jain

    the link to Jessie O’Brien’s article is no longer working. Does anyone know updated url or what it contained?
    Thanks