Laravel Deep Dive: queue system phần 2

Chuẩn bị job cho việc queue

Tất cả các job chúng ta đẩy vào queue đều được lưu trữ trong một không gian lưu trữ riêng và được sắp xếp theo thứ tự thực hiện.

Không gian lưu trữ này sẽ tùy thuộc vào driver mà chúng ta chọn cho việc thực hiện queue: nó có thể là csdl mysql, redis hoặc amazon sqs(simple queue system)... Để thực hiện việc lưu trữ các job ta cần biết các thuộc tính của job sẽ được lưu trữ lại trong hệ thống queue là: * Kiểu hệ thống queue mà chúng ta sẽ thực hiện việc lưu trữ và chạy job * Số lần job có gặp thực hiện (lặp lại job nếu nó bị lỗi) * Thời gian dành cho việc chạy job * Thời gian mà job còn hiệu lực để chạy * Thời gian mà job được tạo * payload của job.

Kiểu của queue nghĩa là gì?

Ứng dụng của ta có thể có nhiều kiểu job khác nhau, mặc định tất cả các job được đẩy vào cùng một queue đơn. Tuy nhiên ta có thể, với một vào job riêng biệt có thể đẩy vào một queue chỉ để thực hiện job đó để đảm các job khác không là chậm quá trình thực hiện job này.

Số lần thực hiện

Mặc định queue manager sẽ có gắng chạy lại job nếu nó chạy lỗi, nó sẽ thực hiện điều này cho đến khi vượt quá số lần mà ta thiết lập, và khi đó job sẽ được đánh dấu là lỗi và sẽ không được chạy lại nữa. Số này bắt đầu từ không.

Thời gian dành cho job

Mỗi job khi được chọn để chạy sẽ có một khoảng thời gian dành cho job đó, khi đó các job ở sau sẽ phải chờ cho đến khi thời gian dành cho job trước hết thì mới có thể được chọn và chạy.

Thời gian sẵn sàng để chạy

Mặc định một job sẵn sàng một khi nó được đẩy và queue và có thể được chọn và chạy ngay. Nhưng đôi khi ta cần hoãn chạy job một khoảng thời gian bằng cách sử dụng phương thức later() thay cho push() cùng với đó là cung cấp thời gian hoãn. Phương thức later() sử dụng phương thức availableAt() để xác định thời gian sẵng sàng của job:

    protected function availableAt($delay = 0)
    {
        return $delay instanceof DateTimeInterface
                            ? $delay->getTimestamp()
                            : Carbon::now()->addSeconds($delay)->getTimestamp();
    }

Như ta thấy ta có thể truyền vào một đối tượng của DateTimeInterface để thiết lập thời gian chính xác hoặc có thể truyền vào số giây và laravel sẽ tính toán thời gian sẵn sàng cho ta.

Payload của job

Phương thức push() và later() sử dụng createPayload() để tạo các thông tin cần cho việc thực hiện job khi được chọn. Ta có 2 cách để truyền job vào queue:

    // Pass an object
    Queue::push(new SendInvoice($order));

    // Pass a string
    Queue::push('App\Jobs\[email protected]', ['order_id' => $orderId])

Ở ví dụ thứ 2 khi job được chọn để thực hiện, Laravel sẽ sử dụng container đẻ tạo ra đối tượng của job của class ta truyền vào, bằng việc này thì ta sẽ dễ dàng thêm các dependency vào thông qua constructor của job.

Tạo payload job từ chuỗi.

Khi tạo payload từ phương thức createPayload(), phương thức này sẽ gọi createPayloadArray(), nếu job truyền vào không phải là một đối tượng thì phương thức createStringPayload() được gọi:

    protected function createStringPayload($job, $data)
    {
        return [
            'displayName' => is_string($job) ? explode('@', $job)[0] : null,
            'job' => $job, 'maxTries' => null,
            'timeout' => null, 'data' => $data,
        ];
    }

displayName là chuỗi ta sử dụng để định danh cho job được chạy, trong trường hợp job không phải là một object ta sử dụng tên class của job cho displayName. Chú ý rằng cũng lưu dữ liệu trong payload của job.

Tạo payload từ một đối tượng job.

    protected function createObjectPayload($job)
    {
        return [
            'displayName' => $this->getDisplayName($job),
            'job' => 'Illuminate\Queue\[email protected]',
            'maxTries' => isset($job->tries) ? $job->tries : null,
            'timeout' => isset($job->timeout) ? $job->timeout : null,
            'data' => [
                'commandName' => get_class($job),
                'command' => serialize(clone $job),
            ],
        ];
    }

Khi chúng ta đã có một đối tượng của job, ta có thể sử dung các thông tin của nó trong quá trình tạo payload của job. Ví dụng sử dụng phương thức getDisplayName() đẻ tìm đến phương thức displayName() trong đối tượng của job, khi tìm thấy nó sẽ trả về tên của job. Vì vậy ta có thể thêm điều khiển tên của job trong queue một cách dễ dàng.

    protected function getDisplayName($job)
    {
        return method_exists($job, 'displayName')
                        ? $job->displayName() : get_class($job);
    }

Ngoài ra các thông tin khác chúng ta có thể khai thác từ đối tượng của job là: số lần job được thử lại, thời gian sẵn sàng của job... nếu ta truyền các giá trị đó vào thì chúng sẽ là dữ liệu cho payload của job được Laravel lưu lại.

Serializing jobs.

Serializing một đối tượng php là việc sinh ra một chuỗi giữ thông tin về class, đối tượng đó, cũng như các trạng thái của nó. Chuỗi này có thể được được sử dụng để tái tạo lại đối tượng. Chúng ta có thể serializing đối tương của job để dễ dàng lưu trữ nó chờ cho đến khi job được chọn và chạy trong hệ thống queue. Trong khi tạo payload cho job từ object ta có thể serialize bản sao của job:

    serialize(clone $job);

Ở đây chúng ta sẽ serialize bản sao của job là do để tránh tác động tới các thuộc tính của đối tượng job mà chúng ta đã khai báo từ trước, vì vậy nó sẽ không ảnh hưởng tới đối tượng gốc.

Kết Luận

Như vậy để chuẩn bị job cho queue ta cần chuẩn bị các thuộc tính của job để lưu trữ lại: loại queue dành cho job, số lần chạy thứ lại job (khi job bị lỗi), thời gian dành cho job, thời gian khi job được chạy, payload của job. Tạo payload của job là quá trình tạo và lưu trữ các thông tin của job được thực hiện bởi Laravel. Có 2 cách tạo payload của job là tạo từ một chuỗi là class job mà ta đã định nghĩa sẵn cùng với data của nó. Ngoài ra ta cũng có thể tạo bằng cách truyền vào một đối tượng của job, khi đó quá trình serialize job sẽ diễn ra để lưu trữ thông tin của job một cách dễ dàng hơn.

Tài liệu tham khảo

  1. https://divinglaravel.com/queue-system/preparing-jobs-for-queue

All Rights Reserved