Tarantool is a NoSQL database and Lua application server. It supports Lua modules, which can be installed with LuaRocks. This package provides PHP bindings for the Tarantool Queue LuaRock.
The recommended way to install the library is through Composer:
composer require tarantool/queueTo use the queue, make sure your Tarantool instance is configured and running. A minimal configuration looks like this:
-- queues.lua
box.cfg {listen = 3301}
queue = require('queue')
queue.create_tube('foobar', 'fifottl', {if_not_exists = true})You can read more about the box configuration in the official Tarantool documentation. More information on queue configuration can be found here.
To start the instance, copy (or symlink) the queues.lua file into the /etc/tarantool/instances.enabled directory
and run the following command:
sudo tt start queuesOnce you have your instance running, create a queue object using the queue (tube) name you defined in the Lua script:
use Tarantool\Queue\Queue;
...
$queue = new Queue($client, 'foobar');where $client is an instance of Tarantool\Client\Client from the tarantool/client package.
If you want PHP to expose only the options supported by a specific built-in queue type, use its typed queue class:
$queue = Queue::fifottl($client, 'foobar');
$task = $queue->put('foo', ttl: 60.0, delay: 5.0);
$limitedQueue = Queue::limfifottl($client, 'bounded');
$taskOrNull = $limitedQueue->put('bar', timeout: 0.0); // null when the queue is fullTyped queue classes describe the queue type expected by the caller; they do not create the tube or verify its server-side type.
The original new Queue($client, $name) API remains available for generic and custom queues.
With this generic API, PHP does not validate option arrays against the queue type; the server-side driver decides whether to accept them.
Its put() method returns Task|null because some drivers can decline a task, for example when a size limit is reached.
For queues with named subqueues, create a Subqueue object once and use it for subsequent operations:
$subqueue = Queue::subqueuettl($client, 'jobs')->subqueue('emails');
$task = $subqueue->put('send message', ttl: 60.0);
$task = $subqueue->take(timeout: 2.0);
$subqueue->ack($task->getId());Subqueue names do not need to be created in advance. Calling subqueue() only creates a PHP object; the driver registers a name when a task is put there. Taking from an empty subqueue returns null. The driver takes from one named subqueue at a time and does not provide a take-from-any-subqueue operation.
Under the hood, Tarantool uses the MessagePack binary format to serialize and deserialize data stored in a queue. It can handle most PHP data types (except resources and closures) without any manual pre- or post-processing:
$queue->put('foo');
$queue->put(true);
$queue->put(42);
$queue->put(4.2);
$queue->put(['foo' => ['bar' => ['baz' => null]]]);
$queue->put(new MyObject());To learn more about object serialization, see User-defined types.
Most Queue API methods return a Task object that provides the following getters:
Task::getId()
Task::getState() // States::READY, States::TAKEN, States::DONE, States::BURY or States::DELAYED
Task::getData()It also provides these convenience methods:
Task::isReady()
Task::isTaken()
Task::isDone()
Task::isBuried()
Task::isDelayed()As you've already seen, to insert a task into a queue, call the put() method. It accepts two arguments: the data you
want to process and an optional array of task options supported by the queue. For example, the fifottl queue, which
we defined earlier in our Lua configuration, supports the delay, ttl, ttr, and pri options:
use Tarantool\Queue\Options;
$queue->put('foo', [Options::DELAY => 30.0]);
$queue->put('bar', [Options::TTL => 5.0]);
$queue->put('baz', [Options::TTR => 10.0, Options::PRI => 42]);See the full list of available options.
To reserve a task for execution, call the take() method. It accepts an optional timeout parameter.
If you supply a timeout, the call waits for up to that many seconds for a READY task to appear in the queue.
The method returns either a Task object or null:
$taskOrNull = $queue->take();
// wait 2 seconds
$taskOrNull = $queue->take(2.0);
// wait 100 milliseconds
$taskOrNull = $queue->take(.1);After successful execution, acknowledge the task to delete it from the queue:
$data = $task->getData();
// process $data
$task = $queue->ack($task->getId());If the task cannot be executed, return it to the queue:
$task = $queue->release($task->getId());
// For *ttl queues, you can specify a delay.
$task = $queue->release($task->getId(), [Options::DELAY => 30.0]);To view a task without changing its state, use:
$task = $queue->peek($task->getId());To bury (disable) a task:
$task = $queue->bury($task->getId());To return buried tasks to the READY state:
$count = $queue->kick(3); // kick 3 buried tasksTo increase the TTR or TTL of a running task (only for *ttl queues):
$taskOrNull = $queue->touch($takenTask->getId(), 5.0); // increase ttr/ttl to 5 secondsYou can permanently delete a task in any state by calling delete():
$task = $queue->delete($task->getId());To delete all tasks in a queue:
$queue->truncate();For a detailed API documentation, please read the section "Using the queue module" of the queue README.
The stats() method returns statistics accumulated since the queue was created:
$stats = $queue->stats();The result of this call might look like this:
[
'tasks' => [
'taken' => 1,
'buried' => 1,
'ready' => 1,
'done' => 0,
'delayed' => 0,
'total' => 3,
],
'calls' => [
'bury' => 1,
'put' => 3,
'take' => 1,
...
],
]In addition, you can specify a key to return only a subset of the array:
$calls = $queue->stats('calls');
$total = $queue->stats('tasks.total');Thanks to the flexibility of the queue Lua module, you can create your own queue
drivers or extend existing ones with additional functionality. For example, suppose you add a put_many method to your
foobar queue to insert multiple tasks atomically:
-- queues.lua
...
queue.tube.foobar.put_many = function(self, items)
local put = {}
box.begin()
for k, item in pairs(items) do
put[k] = tube:put(unpack(item))
end
box.commit()
return put
endTo invoke this method from PHP, use Queue::call():
$result = $queue->call('put_many', [
'foo' => ['foo', [Options::DELAY => 30.0]],
'bar' => ['bar'],
]);The easiest way to run tests is with Docker. First, build an image using the dockerfile.sh generator:
./dockerfile.sh | docker build -t queue -Then run a Tarantool instance (needed for integration tests):
docker network create tarantool-php
docker run -d --net=tarantool-php -p 3301:3301 --name=tarantool \
-v $(pwd)/tests/Integration/queues.lua:/queues.lua \
tarantool/tarantool:2 tarantool /queues.luaThen run both unit and integration tests:
docker run --rm --net=tarantool-php -v $(pwd):/queue -w /queue queueThe tests use PHPUnit. You can pass additional arguments and options to the phpunit command.
For example, run only the unit tests with:
docker run --rm --net=tarantool-php -v $(pwd):/queue -w /queue queue \
vendor/bin/phpunit --testsuite=unitThe library is released under the MIT License. See the bundled LICENSE file for details.