In order to use extension you have to configure it like the following:
return [
'bootstrap' => [
'queue', // The component registers own console commands
],
'components' => [
'queue' => [
'class' => \yii\queue\<driver>\Queue::class,
'as log' => \yii\queue\LogBehavior::class,
// Other driver options
],
],
];
A list of drivers available and their configuration docs is available in table of contents.
Each task which is sent to queue should be defined as a separate class. For example, if you need to download and save a file the class may look like the following:
class DownloadJob extends BaseObject implements \yii\queue\JobInterface
{
public $url;
public $file;
public function execute($queue)
{
file_put_contents($this->file, file_get_contents($this->url));
}
}
Here's how to send a task into queue:
Yii::$app->queue->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
Pushes job into queue that run after 5 min:
Yii::$app->queue->delay(5 * 60)->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
Important: only some drivers support delayed running.
The exact way task is executed depends on the driver used. The most part of drivers can be run using console commands, which the component registers in your application. For more details see documentation of a driver.
The component has ability to track status of a job which was pushed into queue.
// Push a job into queue and get massage ID.
$id = Yii::$app->queue->push(new SomeJob());
// The job is waiting for execute.
Yii::$app->queue->isWaiting($id);
// Worker gets the job from queue, and executing it.
Yii::$app->queue->isReserved($id);
// Worker has executed the job.
Yii::$app->queue->isDone($id);
Important: RabbitMQ driver doesn't support job statuses.
You may pass any data to queue:
Yii::$app->queue->push([
'function' => 'download',
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]);
This is useful if the queue is processed using a specially developer third party worker.
If worker is implemented using something other than PHP you have to change the way data is serialized. For example, to JSON:
return [
'components' => [
'queue' => [
'class' => \yii\queue\<driver>\Queue::class,
'strictJobType' => false,
'serializer' => \yii\queue\serializers\JsonSerializer::class,
],
],
];
Queue triggers the following events:
Event name | Event class | Triggered on |
---|---|---|
Queue::EVENT_BEFORE_PUSH | PushEvent | Adding job to queue using Queue::push() method |
Queue::EVENT_AFTER_PUSH | PushEvent | Adding job to queue using Queue::push() method |
Queue::EVENT_BEFORE_EXEC | ExecEvent | Before each job execution |
Queue::EVENT_AFTER_EXEC | ExecEvent | After each success job execution |
Queue::EVENT_AFTER_ERROR | ErrorEvent | When uncaught exception occurred during the job execution |
cli\Queue:EVENT_WORKER_START | WorkerEvent | When worker has been started |
cli\Queue:EVENT_WORKER_STOP | WorkerEvent | When worker has been stopped |
You can easily attach your own handler to any of these events. For example, let's delay the job, if its execution failed with a special exception:
Yii::$app->queue->on(Queue::EVENT_AFTER_ERROR, function ($event) {
if ($event->error instanceof TemporaryUnprocessableJobException) {
$queue = $event->sender;
$queue->delay(7200)->push($event->job);
}
});
This component provides the LogBehavior
to log Queue events using
Yii built-in Logger.
To use it, simply configure the Queue component as follows:
return [
'components' => [
'queue' => [
'class' => \yii\queue\redis\Queue::class,
'as log' => \yii\queue\LogBehavior::class
],
],
];
Configuration example:
return [
'bootstrap' => [
'queue1', // First component registers own console commands
'queue2', // Second component registers own console commands
],
'components' => [
'queue1' => [
'class' => \yii\queue\redis\Queue::class,
],
'queue2' => [
'class' => \yii\queue\db\Queue::class,
'strictJobType' => false,
'serializer' => \yii\queue\serializers\JsonSerializer::class,
],
],
];
Usage example:
// Sending task to queue to be processed via standard worker
Yii::$app->queue1->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
// Sending tasks to another queue to be processed by third party worker
Yii::$app->queue2->push([
'function' => 'download',
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]);
When using queues it's important to remember that tasks are put into queue and are obtained from queue in separate processes. Therefore avoid external dependencies when executing a task if you're not sure if they are available in the environment where it worker does its job.
All the data to process the task should be put into properties of your job object and sent into queue along with it.
If you need to process ActiveRecord
then send its ID instead of the object itself. When processing you have to extract
it from DB.
For example:
Yii::$app->queue->push(new SomeJob([
'userId' => Yii::$app->user->id,
'bookId' => $book->id,
'someUrl' => Url::to(['controller/action']),
]));
Task class:
class SomeJob extends BaseObject implements \yii\queue\JobInterface
{
public $userId;
public $bookId;
public $someUrl;
public function execute($queue)
{
$user = User::findOne($this->userId);
$book = Book::findOne($this->bookId);
//...
}
}