Laravel: Tìm hiểu về queues. (Phần 2)

https://viblo.asia/p/laravel-tim-hieu-ve-queues-phan-2-yMnKMgpal7P

Laravel: Tìm hiểu về queues. (Phần 2)

Bài đăng này đã không được cập nhật trong 4 năm

Running The Queue Worker

Laravel bao gồm một queue worker sẽ xử lý các new job khi nó được đẩy lên queue. Bạn có thể chạy các worker bằng cách sử dụng Artisan command queue:work. Lưu ý rằng khi câu lệnh queue:work được chạy, nó sẽ tiếp tục chạy cho đến khi nó được dừng bằng tay hoặc khi bạn đóng terminal:

php artisan queue:man_construction_worker:

Hãy nhớ rằng, các queue worker là các quy trình tồn lại lâu và lưu trữ trạng thái ứng dụng khởi động trong bộ nhớ. Do đó, nó sẽ không nhận thấy sự thay đổi trong code base của bạn sau khi chúng đã được bắt đầu. Vì vậy, trong quá trình triển khai của bạn, hãy chắc chắn khởi động lại queue worker của bạn.

Processing A Single Job

Tùy chọn --once có thể được sử dụng để hướng dẫn worker chỉ xử lý một job từ queue:

php artisan queue:work --once

Specifying The Connection & Queue Bạn cũng có thể chỉ định queue connection mà worker nên sử dụng. Tên connection được chuyển tới lệnh work phải tương ứng với một trong các connection đã được định nghĩa bên trong file cấu hình config/queue.php:

php artisan queue:work redis

Bạn có thể tùy chỉnh queue worker của bạn hơn nữa bằng cách chỉ xử lý các queue cụ thể cho một connection nhất định. Ví dụ: nếu tất cả email của bạn được xử lý trong một email queue trên redis queue connection của bạn, bạn có thể đưa ra kệnh sau để start một worker chỉ xử lý queue đó:

php artisan queue:work redis --queue=emails

Queue Priorities

Đôi khi bạn muốn ưu tiên queue của bạn được xử lý như thế nào. Ví dụ, trong file config/queue.php của bạn, bạn có thể thiết lập default queue cho redis connection của bạn ở mức thấp. Tuy nhiên, đôi khi bạn có thể muốn đẩy một job lên trên queue được ưu tiên cao như sau:

dispatch((new Job)->onQueue('high'));

Để bắt đầu một worker được kiểm chứng rằng tất cả các high queue job được xử lý trước khi tiếp tục bất kỳ job nào tròng low queue, hãy chuyển một danh sách các tên queue được phân cách nhau bằng dấu phảy vào lệnh work:

php artisan queue:work --queue=high,low

Queue Workers & Deployment

Vì các queue worker là các process tồn tại lâu dài, chúng sẽ không nhận các thay đổi đối với code của bạn mà không khởi động lại. Vì vậy, cách đơn giản nhất để triển khai ứng dụng sử dụng các queue worker là khởi động lại worker trong quá trình phát triển của bạn.Bạn có thể khởi động lại tất cả các worker bằng cách sử dụng câu lệnh queue:restart:

php artisan queue:restart

Lệnh này sẽ dạy tất cả queue worker die một cách duyên dáng sau khi chúng kết thúc job hiện tại để không có job nào tồn tại bị mất. Kể từ khi các queue worker sẽ chết khi câu lệnh queue:restart được thực thi, bạn nên chạy một trình quản lý process như Supervisor để tự động khởi động lại các queue worker.

Job Expirations & Timeouts

Job Expiration

Trong file cấu hình config/queue.php của bạn, mỗi queue connection định nghĩa một tùy chọn retry_after. Tùy chọn này chỉ định bao nhiêu giây queue connection nên đợi trước khi thử lại một job đang được xử lý. Ví dụ: nếu giá trị retry_after được đặt là 90, job sẽ được giải phóng trở lại queue nếu nó đã ddwwocj xử lý trong 90 giây mà không bị xóa. Thông thường, bạn nên đặt giá trị retry_after tới số giây tối đa mà job của bạn càn phải làm để hoàn tất quá trình xử lý.

Worker Timeouts

Câu lệnh Artisan queue:work đặt ra một tùy chọn --timeout. Tùy chọn --timeout chỉ định khoảng thời gian mà Laravel queue master process sẽ đợi trước khi kill một child queue worker đang xử lý một job. Đôi khi một child queue có thể trở nên "frozen" vì nhiều lý do, chẳng hạn như gọi HTTP bên ngoài không được đáp ứng (not respond). Tùy chọn --timeout loại bỏ quá trình đóng băng đã vượt quá giớn hạn thời gian chỉ định:

php artisan queue:work --timeout=60

Tùy chọn cấu hình retry_after và tùy chọn CLI timeout là khác nhau, nhưng làm việc cùng nhau để đảm bảo rằng job không bị mất và các job chỉ được xử lý thành công 1 lần.

Worker Sleep Duration

Khi các job có sẵn trên queue, worker sẽ tiếp tục các processing job mà không có delay giữa chúng. Tuy nhiên, tùy chọn sleep sẽ xác định khoảng thời gian worker sẽ "sleep" nếu không có job có sẵn mới. Trong khi ngủ, worker sẽ không tiên hành bất cứ 1 job mới nào- job sẽ được xử lý sau khi worker thức dậy.

php artisan queue:work --sleep=3

Supervisor Configuration

Installing Superviso

Supervisor là một quá trình giám sát cho hệ điều hành Lunux, và sẽ tự động khởi động lại queue:work của bạn nếu nó có lỗi. Để cài đặt Supervisor trên Ubuntu, bạn có thể sử dụng lệnh sau:

sudo apt-get install supervisor

Configuring Supervisor

File cấu hinh của Supervisor thường được lưu trong thư mục /etc/supervisor/conf.d. Trong thư mục này, bạn có thể tạo ra bất kỳ số file cấu hình nào hướng dẫn người giám sát kiểm soát các quy trình của bạn. Ví dụ, chúng ta hãy tạo 1 file laravel-worker.conf bắt đầu và giám sát queue:work làm việc:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3
autostart=true
autorestart=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log

Trong ví dụ này, lệnh numprocssẽ instruct Supervisor chạy 8 queue:work và giám sát tất cả chúng, tự động khởi động lại chúng nếu chúng fail. Tất nhiên, bạn nên thay đổi queue:work sqs của command directive để phản ánh queue connection. Starting Supervisor Khi file cấu hình đã được tạo, bạn có thể cập nhật cấu hình Supervisor và bắt đầu các quá trình sử dụng theo lệnh sau:

sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start laravel-worker:*

Bạn có thể tham khảo thêm tại Supervisor documentation

Dealing With Failed Jobs

Đôi khi các job queue của bạn sẽ fail. Đừng lo lắng, mọi thứ không phải luôn đi theo kế hoạch. Laravel có một cách thuận tiện để xác định số lần tối đa một job nên được cố gắng thực hiện. Sau khi hob vượt quá số lần thử này, nó sẽ được đưa vào bảng failed_jobs trong database. Để tạo một migration cho bảng failed_jobs, bạn có thể sử dụng câu lệnh queue:failed-table

php artisan queue:failed-table

php artisan migrate

Sau đó, khi chạy queue worker của bạn, bạn nên xác định số lần tối đa một job được cố gắng thực hiện bằng cách sử dụng lệnh --tries trên queue:work. Nếu bạn không chỉ định giá trị cho tùy chọn --tries, job sẽ được thực hiện vô thời hạn:

php artisan queue:work redis --tries=3

Cleaning Up After Failed Jobs

Bạn có thể định nghĩa một phương thức failed trực tiếp trên job class của bạn, cho phép bạn thực hiện job một cách clean-up khi xảy ra sự cố. Đây là vị trí hoàn hảo để gửi cảnh báo cho người dùng của bạn hoặc revert bất kỳ hành động nào được thực hiện bởi job. Các Exception khiên job bị fail sẽ được chuyển đến failed method.

<?php

namespace App\Jobs;

use Exception;
use App\Podcast;
use App\AudioProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessPodcast implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    protected $podcast;

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

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

    /**
     * The job failed to process.
     *
     * @param  Exception  $exception
     * @return void
     */
    public function failed(Exception $exception)
    {
        // Send user notification of failure, etc...
    }
}

Failed Job Events

Nếu bạn muốn đăng ký một event được gọi khi job bị fail, bạn có thể sử dụng phương thức Queue::failing. Event này là cơ hội tuyệt vời để thông báo cho nhón của bạn qua email hoặc HipChat. Ví dụ: chúng ta có thể đính kèm một callback cho event từ AppServiceProvider có sẵn trong Laravel:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Queue;
use Illuminate\Queue\Events\JobFailed;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Queue::failing(function (JobFailed $event) {
            // $event->connectionName
            // $event->job
            // $event->exception
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Retrying Failed Jobs

Để xem tất cả các job thất bại đã được chèn vào bảng failed_jobs trong DB của bạn, bạn có thể sử dụng câu lệnh Artisan queue:failed:

php artisan queue:failed

Lệnh queue:failed sẽ liệt kê ra job ID, connection, queue, và failure time. job IDcó thể được sử dụng để thử lại job không thành công. Ví dụ, để thử lại một job không thành công có ID là 5, ta sử dụng lệnh sau:

php artisan queue:retry 5

Để thử lại tất cả các job không thành công của bạn, hãy thực hiện lệnh queue:retry và truyền alll giống như ID:

php artisan queue:retry all

Nếu bạn muốn xóa một job không thành công, bạn có thể sử dụng queue:forget:

php artisan queue:forget 5

Để xóa tất cả các job thất bại của bạn, bạn có thể sử lệnh queue:flush:

php artisan queue:flushed:

Job Events

Sử dụng các phương thức beforeafter trên Queue facade, bạn có thể chỉ định các callback để được thực hiện trước hoặc sau khi một queue job được xử lý. Những callback này là một cơ hội tuyệt vời để thực hiện thêm các Logging hoặc thống kê cho bashboard. Thông thường, bạn nên gọi các phương thức này từ service provider. Ví dụ: chúng ta có thể sử dụng AppServiceProvider có trong Laravel:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Queue;
use Illuminate\Support\ServiceProvider;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Queue::before(function (JobProcessing $event) {
            // $event->connectionName
            // $event->job
            // $event->job->payload()
        });

        Queue::after(function (JobProcessed $event) {
            // $event->connectionName
            // $event->job
            // $event->job->payload()
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Bằng cách sử dụng phương thức lặp trên Queue facade, bạn có thể chỉ định các callback thực hiện trước khi worker tìm cách lấy một job từ hàng đợi. Ví dụ, bạn có thể đăng ký một Closure để rollback bất kỳ transaction bởi một công việc thất bại trước đây:

Queue::looping(function () {
    while (DB::transactionLevel() > 0) {
        DB::rollBack();
    }
});

Tài liệu: Tại trang chủ của Laravel

Last updated