Laravel: Tìm hiểu về queues. (Phần 2)
Bài đăng này đã không được cập nhật trong 6 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 numprocs
sẽ 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 before
và after
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
All rights reserved