Using RabbitMQ

The RabbitMQ adapter uses the php-amqplib library.

You need to require the library in composer:

{
    "require": {
        "myclabs/work": "*",
        "videlalvaro/php-amqplib": "~2.0"
    }
}

This following is inspired from the official RabbitMQ docs, you should read them first.

On your client side (MVC application for example):

// Connect to the RabbitMQ server
$connection = new AMQPConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// Create a queue
$channel->queue_declare('some_queue', false, false, false, false);

$workDispatcher = new RabbitMQWorkDispatcher($channel, 'some_queue');

// Run a task in background
$task = new MyTask();
$workDispatcher->run($task);

On the worker side (this script is meant to be run continuously as a deamon):

// Connect to the RabbitMQ server
$connection = new AMQPConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// Create a queue
$channel->queue_declare('some_queue', false, false, false, false);

$worker = new RabbitMQWorker($channel, 'some_queue');
$worker->registerTaskExecutor('MyTask', new MyTaskExecutor());

// Execute tasks
$worker->work();

Waiting for a task to finish

In some setups, you might want to wait for a task to finish executing.

For example, you may want to execute a task in background and:

  • either display a message on the webapp (in the HTTP response) if the task finished in less than 5 seconds
  • or notify a user by email later if the task takes more than 5 seconds

In short, your webapp will send the task to be run in background, and wait for 5 seconds to see if it finishes.

The RabbitMQ adapter implements the SynchronousWorkDispatcher which makes that possible.

Here is a schema of how it works internally using RabbitMQ:

Diagram

On you client side, you can use runAndWait like so:

$completed = function () {
    echo "The operation has completed.";
}
$timeout = function () {
    echo "The operation is being applied. You will be emailed when it has completed.";
    // to notify the user, see below
}
$error = function (Exception $e) {
    echo "There was an error while completing the operation!";
}

// Wait for 5 seconds
$workDispatcher->runAndWait($task, 5, $completed, $timeout, $error);

This will run the task in the worker and wait for 5 seconds for a result. If the worker finishes in less than 5 seconds, then the $completed or $error callback will be called. Else, the $timeout callback will be called.

On the worker side, you can use events to email the user depending on whether the task finished in less than 5 seconds or not:

public function onTaskSuccess(Task $task, $dispatcherNotified)
{
    // If the request that sent the task wasn't notified that the task was over
    // (i.e. if the task took more than 5 seconds)
    if (!$dispatcherNotified) {
        // Then we send an email to the user to alert him/her
        sendEmailToUser("The operation has now completed.");
    }
}
public function onTaskError(Task $task, Exception $e, $dispatcherNotified)
{
    if (!$dispatcherNotified) {
        sendEmailToUser("There was an error while completing the operation!");
    }
}