Hướng dẫn dùng Phalcon với PHP-Resque

Hôm nay trong bài viết này tôi sẽ hướng dẫn bạn sử dụng một thư viện php-resque tương tác queue, như các bạn biết có khá nhiều dịch vụ như RabbitMQ, Beanstalk, etc, tại sao tôi lại dùng nó thứ nhất vì thư viện này viết bằng PHP, sau đó nó lại kết hợp với Redis để lưu trữ các thông tin của jobs queue đó, và tất nhiên nó khá là dễ sử dụng.

Nếu bạn muốn xem video cách dùng nó như thế nào thì bạn có thể xem khoá học Phalcon căn bản . Trước hết bạn cần hiểu khái niệm Message Queue là gì: Theo như sự hiểu biết của tôi thì Message Queue là một mô hình giao tiếp truyền tin bất động bộ. Có nghĩa trao đổi giữa người gửi và người nhận không cần xảy ra đồng thời, tại cùng 1 thời điểm. Người gửi có thể đẩy tin cần gửi vào hàng đợi (queue), và sau đó một số tiến trình độc lập (worker) sẽ đẩy tin từ hàng đợi đến người nhận.

Lấy một ví dụ cụ thể như thế này, chẵn hạn bạn có chức năng đăng ký người dùng, thì khi người dùng điền thông tin, bạn sẽ đặt một job vào queue đó, job này có nhiệm vụ gửi link để kích hoạt tài khoản, bạn có thể chạy sau một phút hoặc một giờ tùy bạn định nghĩa thời gian.
$this->queue->enqueue('gsviec_sendmail', '\\App\Queue\MailQueue', $params);

Cài đặt PHP-resque

Như mọi khi bạn nên cài đặt thư viện PHP thông qua composer nếu bạn chưa biết nó là gì thì hãy search từ khóa đó với google để hiểu nó. Mở file composer.jon chèn nội dung giống như
{
    "require": {
        "swiftmailer/swiftmailer": "^6.0",
         "chrisboulton/php-resque": "dev-master"
    }
}
Sau đó bạn chạy lệnh composer install, để cài đặt thư viện php-resque. Sau khi cài đặt xong tạo một file cấu hình tùy vào mỗi một framework PHP cụ thể mà bạn đặt cấu hình của PHP-Resque, để cho đơn giản tôi tạo một file settings.php với nội dung sau:
$settings = [
    'REDIS_BACKEND'    => 'localhost:6379',  // Set Redis Backend                                'REDIS_BACKEND_DB'  => '0',   // Use Redis DB 0
    'COUNT'             => '1',   // Run 1 worker
    'INTERVAL'          => '5',   // Run every 5 seconds
    'QUEUE'             => '*',   // Look in all queues
    'PREFIX'            => 'gsviec_',  // Prefix queues 
    'VVERBOSE'          => '1',
    'APP_INCLUDE'       => 'run'
],
foreach ($settings as $key => $value) {
     putenv(sprintf('%s=%s', $key, $value));
}
Còn trong dự án thực tế của tôi sẽ giống như thế này, chú ý đây là code khi tôi dùng Framework Phalcon PHP
<?php

namespace App\Queue;

use Phalcon\Mvc\User\Component;

class Resque extends Component
{

    public function __construct()
    {

        $resque = (array) $this->config->resque;

        foreach ($resque as $key => $value) {
            putenv(sprintf('%s=%s', $key, $value));
        }
        //Set prefix
        \Resque_Redis::prefix(getenv('PREFIX'));
        \Resque::setBackend(getenv('REDIS_BACKEND'));
    }


    /**
     * Create a new job and save it to the specified queue.
     *
     * @param string $queue The name of the queue to place the job in.
     * @param string $class The name of the class that contains the code to execute the job.
     * @param array $args Any optional arguments that should be passed when the job is executed.
     * @param boolean $trackStatus Set to true to be able to monitor the status of a job.
     *
     * @return string|boolean Job ID when the job was created, false if creation was cancelled due to beforeEnqueue
     */
    public function enqueue($queue, $class, $args = null, $trackStatus = false)
    {
        return \Resque::enqueue($queue, $class, $args, $trackStatus);
    }
    public function blpop(array $queues, $timeout)
    {
        return \Resque::blpop($queues,$timeout);
    }
    public function tracking($token)
    {
        return new \Resque_Job_Status($token);
    }
}
Trong đó tham số QUEUE = * có nghĩa là chạy toàn bộ jobs có hiện tại nếu bạn muốn chỉ chạy mỗi job khôi phục mật khẩu thì lúc này tham số QUEUE = ‘gsviec_sendmail’, INTERVAL : có nghĩa là thời gian thực thi các jobs mặc định là 5 giây, dưới đây là một ví dụ khi tôi capture.
# tail -f /tmp/resque/admin/resque
[info] [03:29:03 2016-11-30] Checking signupinitial for jobs
[info] [03:29:03 2016-11-30] Sleeping for 5
[info] [03:29:08 2016-11-30] Checking influxdb for jobs
[info] [03:29:08 2016-11-30] Checking gsviec_sendmail for jobs
[info] [03:29:08 2016-11-30] Checking signupinitial for jobs
[info] [03:29:08 2016-11-30] Sleeping for 5
[info] [03:29:13 2016-11-30] Checking influxdb for jobs
[info] [03:29:13 2016-11-30] Checking gsviec_sendmail for jobs
[info] [03:29:13 2016-11-30] Checking signupinitial for jobs
[info] [03:29:13 2016-11-30] Sleeping for 5
[info] [03:29:18 2016-11-30] Checking influxdb for jobs
[info] [03:29:18 2016-11-30] Checking gsviec_sendmail for jobs
[info] [03:29:18 2016-11-30] Checking signupinitial for jobs
[info] [03:29:18 2016-11-30] Sleeping for 5
PREFIX: thêm vào khi bạn có nhiều jobs tránh conflict nó cũng như giúp ta định danh jobs nó dễ hơn, APP_INCLUDE: là file dùng để load các thư viện, trong dự án của tôi thì có dạng như thế này.
<?php
use Phalcon\Di\FactoryDefault\Cli as CliDi;
use Phalcon\Cli\Console as ConsoleApp;
define('ROOT_DIR', dirname(__DIR__));
/**
 * The FactoryDefault Dependency Injector automatically registers the services that
 * provide a full stack framework. These default services can be overidden with custom ones.
 */
$di = new CliDi();
require ROOT_DIR . "/cli/config/loader.php";
/**
 * Include Services
 */
include ROOT_DIR . '/cli/config/service.php';
/**
 * Create a console application
 */
$console = new ConsoleApp($di);
/**
 * Process the console arguments
 */
$arguments = [];
foreach ($argv as $k => $arg) {
    if ($k == 1) {
        $arguments['task'] = $arg;
    } elseif ($k == 2) {
        $arguments['action'] = $arg;
    } elseif ($k >= 3) {
        $arguments['params'][] = $arg;
    }
}
try {
    if (getenv('QUEUE')) {
        return 0;
    }
    /**
     * Handle
     */
    $console->handle($arguments);
    /**
     * If configs is set to true, then we print a new line at the end of each execution
     *
     * If we dont print a new line,
     * then the next command prompt will be placed directly on the left of the output
     * and it is less readable.
     *
     * You can disable this behaviour if the output of your application needs to don't have a new line at end
     */
    if (isset($config["printNewLine"]) && $config["printNewLine"]) {
        echo PHP_EOL;
    }
} catch (Exception $e) {
    echo $e->getMessage() . PHP_EOL;
    echo $e->getTraceAsString() . PHP_EOL;
    exit(255);
}
VVERBOSE: nếu bạn muốn bật chế độ debug thì gán cho 1 mặc định là 0 các tham số còn lại bạn có thể tham khảo trên trang chủ của nó https://github.com/chrisboulton/php-resque. Tạo một job sau khi bạn đã cấu hình xong thì bạn cần tạo job cho nó, ví dụ job gsviec_sendmail.
<?php
namespace App\Queue;
class MailQueue extends Resque
{
    /**
    * Set up environment for this job
    *
    */
    public function setUp()
    {
        
    }

    /**
     * Run a job
     *
     */
    public function perform()
    {
        $params = $this->args;
        //var_dump($params);
        $email = $params['email'];
        if (!$this->mail->send($email, 'reset', $params)) {
            throw new \Exception('Something wrong');
        }
    }
    **
    * Remove environment for this job
    *
    */
    public function tearDown()
    {

    }
}
Khi dùng Resques chúng ta có ba method đó là: setUp: Phương thức này chạy trước khi bạn thực hiện job thường dùng đê kết nối redisperform: Công việc cần làm như trong ví dụ trên tôi gửi email tearDown: Làm những công việc sau khi xong job như xóa biến tạm , đối tượng, etcNó thực sự rất giống trong các hàm unit test nếu như bạn nào thường viết test case cho các ứng dụng PHP. Để kiểm tra nó có làm việc hay không bạn chỉ cần nhập email, username vào sau đó bấm đăng ký, đây sẽ là kết quả bạn mong đợi khi chạy log.
[info] [03:45:28 2016-11-30] Checking influxdb for jobs
[info] [03:45:28 2016-11-30] Checking gsviec_sendmail for jobs
[info] [03:45:28 2016-11-30] Checking signupinitial for jobs
[info] [03:45:28 2016-11-30] Sleeping for 5
[info] [03:45:33 2016-11-30] Checking influxdb for jobs
[info] [03:45:33 2016-11-30] Checking gsviec_sendmail for jobs
[info] [03:45:33 2016-11-30] Found job on gsviec_sendmail
[notice] [03:45:33 2016-11-30] Starting work on (Job{gsviec_sendmail} | ID:4bffd39dbcd729fa60fcc22bf7ea7b24[{'username': 'duythien', 'email': '[email protected]'.....}]

Kết luận

Trong bài viết này tôi đã hướng dẫn các bạn dùng PHP-Resque với Phalcon PHP, nếu bạn có dùng nó cho các FW khác thì để bình luận dưới đây, như mọi khi nếu thấy bài viết hay thì share!!!

Leave a Reply

Your email address will not be published. Required fields are marked *