Очередь задач на PHP на Doctrine2

Опубликовано admin в

Бывают ситуации когда нет смысла использовать серверы очередей, типа Rabbitmq, German, etc. Была задача — отправка писем пользователям, проверка на поступление оплаты.

Для этого было решено написать простой класс, который считывает сообщения из таблицы, удаляет сообщения, добавлят задачу в таблицу.

На тот момент я решил задачу с помощью Doctrine 2 + CI 2. Надеюсь, что общий принцип будет понятен, и это решение вы сможете подстроить под себя.

Начнём с модели:

<?php

namespace Entity;

/**
 * Описание модели "Задачи для робота"
 *
 * @Entity
 * @Table(name="tasks")
 */
class Task extends BaseEntity {
    /**
     * @Column(type="string", length=115, nullable=true)
     */
    protected $type;
    /**
     * @Column(type="array", nullable=true)
     */
    protected $params;
    /**
     * @Column(type="boolean", nullable=true)
     */
    protected $status = false;

    public function __construct()
    {
    }

    /**
     * Тип задачи (отправка рассылки, отправка письма, обновление статуса конкурса)
     *
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    public function setType($type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * Параметры для выполнения (это массив, который будет передан в метод для выполнения)
     * @return array
     */
    public function getParams()
    {
        return $this->params;
    }

    public function setParams($params)
    {
        $this->params = $params;
        return $this;
    }

    /**
     * Статус задачи (выполнена, не выполнена)
     *
     * @return string
     */
    public function getStatus()
    {
        return $this->status;
    }

    public function setStatus($status)
    {
        $this->status = $status;
        return $this;
    }
}

setParams — добавляет необходимые параметры к задаче ввиде массива, преобразованием массива занимается Doctrine. Вы можете сериализовать массив, сохранить, затем десериализовать — serialize

Теперь, добавим нужную задачу:

$hello_world_task = new Entity\Task;
$hello_world_task->setType('hello_world')->setParams(['key1' => 'value1', 'key2' => 'value2']);

$this->tasks->addTask($hello_world_task);

Создадим контроллер, который будет запускаться cron-ом:

class Robot extends CI_Controller
{
    public $doctrine;

    public function __construct()
    {
        parent::__construct();
        if (php_sapi_name() !== 'cli') {
            show_404();
        } else {
            $this->load->library(['doctrine', 'tasks']);
            $this->doctrine = $this->doctrine->em;
        }
    }

    /**
     * Запуск задач
     */
    public function run_tasks()
    {
        $tasks = $this->tasks->getTasks();

        foreach ($tasks as $task) {
            switch ($task->getType()) {
                // Отправка рассылки
                case 'hello_world':
                    $this->hello_world_worker($task);
                    break;
            }
        }
    }

    private function hello_world_worker(\Entity\Task $task)
    {
        $params = $task->getParams();

        foreach ($params as $key => $value) {
            echo "$key - $value";
        }

        $this->tasks->deleteTask($task);
    }
}

Теперь осталось добавить задачу в cron*/15 * * * * php /path/to/index.php robot run_tasks

И добавим саму библиотеку, в папку libraries:

class Tasks {

    private $ci;

    public function __construct($params = null)
    {
        $this->ci =& get_instance();
    }

    public function getTasks()
    {
        $tasks = $this->ci->doctrine
                          ->getRepository('Entity\Task')
                          ->findBy(array('status' => false));

        return $tasks;
    }

    public function addTask(\Entity\Task $task)
    {
        $this->ci->doctrine->persist($task);
        $this->ci->doctrine->flush();

        return $this;
    }

    public function deleteTask(\Entity\Task $task)
    {
        $this->ci->doctrine->remove($task);
        $this->ci->doctrine->flush();

        return $this;
    }
}

Источник

Рубрики: PHP