12/08/2018, 16:21

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

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 ...

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 ````timeoutlà 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ọnsleep``` 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

<br>
**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 AppJobs; use Exception; use AppPodcast; use AppAudioProcessor; use IlluminateBusQueueable; use IlluminateQueueSerializesModels; use IlluminateQueueInteractsWithQueue; use IlluminateContractsQueueShouldQueue; 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](https://www.stride.com/). Ví dụ: chúng ta có thể đính kèm một callback cho event từ ```AppServiceProvider``` có sẵn trong Laravel: ``` <?php namespace AppProviders; use IlluminateSupportFacadesQueue; use IlluminateQueueEventsJobFailed; use IlluminateSupportServiceProvider; 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](https://laravel.com/docs/5.4/facades), 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](https://laravel.com/docs/5.4/providers). Ví dụ: chúng ta có thể sử dụng ```AppServiceProvider``` có trong Laravel: ``` <?php namespace AppProviders; use IlluminateSupportFacadesQueue; use IlluminateSupportServiceProvider; use IlluminateQueueEventsJobProcessed; use IlluminateQueueEventsJobProcessing; 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](https://laravel.com/docs/5.4/facades), 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](https://laravel.com/docs/5.4/queues)_
0