14/09/2018, 14:18

Laravel Queue

1. Queue là gì Hàng đợi cho phép bạn trì hoãn một công việc mất nhiều thời gian đến một thời điểm nào nó mới xử lý. Laravel cung cấp một API thống nhất cho rất nhiều các hàng đợi ở backend khác nhau. Để hiểu nhanh các khái niệm mới chúng ta hãy bắt đầu bằng ví dụ: Bạn hãy tưởng tượng website ...

1. Queue là gì

Hàng đợi cho phép bạn trì hoãn một công việc mất nhiều thời gian đến một thời điểm nào nó mới xử lý. Laravel cung cấp một API thống nhất cho rất nhiều các hàng đợi ở backend khác nhau. Để hiểu nhanh các khái niệm mới chúng ta hãy bắt đầu bằng ví dụ: Bạn hãy tưởng tượng website của bạn có nhiều người vào xem và có thể đăng ký tài khoản, người đó đang ở trang đăng ký và nhập các thông tin vào form đăng ký. Khi đó chúng ta muốn thực hiện các công việc sau:

  • Kiểm tra thông tin nhập và lưu vào CSDL.
  • Gửi một email Chào mừng đến thành viên mới này.
  • Trả về trang Thankyou.

Sau khi kiểm tra và lưu thông tin vào CSDL, tiếp tục đến phần việc gửi email do mã PHP thực hiện tuần tự từ trên xuống. Người dùng sẽ thấy trang Thankyou nếu email đã được gửi đi, quá trình gửi email có thể nhanh nhưng cũng có thể mất thời gian, vậy tại sao phải bắt người dùng chờ? Laravel Queue sẽ là cứu cánh cho tình huống này.

2. Laravel Queue là gì

Một hàng đợi (queue) là một danh sách những việc cần làm (job) được quản lý theo thứ tự. Khi chúng ta muốn thêm một công việc (job) vào hàng đợi, job phải implement interface IlluminateContractsQueueShouldQueue.

Laravel Queue driver được sử dụng để quản lý các job như thêm job vào hàng đợi, lấy job ra khỏi hàng đợi. Laravel có thể làm việc với nhiều các driver khác nhau như database, Redis, Amazon SQS… và bạn có thể tự tạo riêng một driver nếu muốn. Trong bài viết này, chúng ta sẽ lưu trữ các job trong database, để thực hiện việc này, thực hiện các câu lệnh artisan để tạo ra các bảng lưu trữ trong database như sau:

php artisan queue:table
php artisan queue:failed-table

Các câu lệnh này sẽ tạo ra bảng jobs và failed_jobs trong cơ sở dữ liệu. Ngoài ra, cần phải thiết lập

QUEUE_DRIVER=database

trong file cấu hình biến môi trường .env ở thư mục gốc project.

Mặc định, các job được lưu trong appJobs, nếu thư mục appJobs không có trong project bạn cũng đừng lo, câu lệnh tạo job sẽ tự động tạo ra thư mục này nếu chưa có. Thực hiện tạo một job mới bằng câu lệnh:

php artisan make:job SendWelcomeEmail

Nó sẽ tự động sinh ra job SendWelcomeEmail được implement interface IlluminateContractsQueueShouldQueue. Class này chứa phương thức handle() sẽ được gọi đến khi job được xử lý trong hàng đợi. Chúng ta hãy xem khung của một job:

<?php

namespace AppJobs;

use AppUser;
use AppAudioProcessor;
use IlluminateBusQueueable;
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldQueue;

class SendWelcome Email implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    protected $user;

    /**
     * Create a new job instance.
     *
     * @param  User  $user
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Execute the job.
     *
     * @param  AudioProcessor  $processor
     * @return void
     */
    public function handle(AudioProcessor $processor)
    {
        // Process uploaded user...
    }
}

Trong ví dụ trên chúng ta truyền một Eloquent Model User vào phương thức contruct của job. Để thêm job vào một queue, sử dụng phương thức dispatch(): trong controller RegisterController

<?php
namespace AppHttpControllersAuth;
use AppUser;
use AppHttpControllersController;****
use IlluminateSupportFacadesValidator;
use IlluminateFoundationAuthRegistersUsers;
use AppJobsSendWelcomeEmail;
class RegisterController extends Controller
{
    ...
    protected function create(array $data)
    {
        $user = User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
        $job = (new SendWelcomeEmail($user))->delay(Carbon::now()->addMinutes(10));
        dispatch($job);
        return $user;
    }
}

Phương thức delay() sẽ dừng lại trước khi thực hiện job trong queue. Nó sẽ delay thêm 10 phút

3. Thực thi các jobs trong queue

3.1 Số lần thử thực hiện job

Mặc định job sẽ được thực hiện 1 lần, nếu lỗi sẽ được bỏ qua, để thiết lập số lần thử thực hiện lại một job chúng ta có hai cách: hoặc sử dụng câu lệnh artisan cho tất cả các job

php artisan queue:work --tries=3

hoặc đưa vào thuộc tính $tries của từng job

<?php
namespace AppJobs;

class SendWelcome implements ShouldQueue
{
    /**
     * Số lần job sẽ thử thực hiện lại
     *
     * @var int
     */
    public $tries = 3;
}

3.2 Thiết lập thời gian timeout của job trong queue

Bạn có thể thiết lập thời gian timeout của các job bằng cách sử dụng câu lệnh artisan

php artisan queue:work --timeout=60

hoặc thiết lập trong thuộc tính $$imeout của từng job

<?php
namespace AppJobs;

class SendWelcome implements ShouldQueue
{
    /**
     * Số giây job có thể chạy trước khi timeout
     *
     * @var int
     */
    public $timeout = 60;
}

3.3 Queue worker, thực thi các job trong queue

Laravel có một queue worker để thực thi các job đang có trong hàng đợi, bạn có thể chạy worker này bằng câu lệnh artisan:

php artisan queue:work

Chú ý, câu lệnh này khi đã thực hiện sẽ chạy cho đến khi đóng cửa sổ dòng lệnh hoặc dừng nó bằng một câu lệnh. Queue worker là các tiến trình có thời gian sống dài do đó nó sẽ không cập nhật code khi có thay đổi, khi bạn thay đổi code chương trình, bạn cần khởi động lại queue worker bằng câu lệnh

php artisan queue:restart

Thiết lập thời gian nghỉ giữa các lần xử lý job Các job trong hàng đợi được xử lý liên tục mà không có sự dừng lại nào, tùy chọn sleep sẽ xác định worker dừng lại sau bao lâu trước khi tiếp tục xử lý job tiếp theo:

php artisan queue:work --sleep=3

4.

0