Trong quá trình phát triển ứng dụng web, có thể xuất hiện các tác vụ mà việc thực hiện chúng, như phân tích cú pháp hoặc lưu trữ tệp CSV đã tải lên, tốn rất nhiều thời gian trong một yêu cầu web thông thường. Tuy nhiên với Laravel, bạn có thể dễ dàng tạo các Jobs được xếp hàng đợi để xử lý ở chế độ nền. Bằng cách đưa các tác vụ tốn nhiều thời gian vào hàng đợi, ứng dụng của bạn có thể nhanh chóng đáp ứng các yêu cầu web và cung cấp trải nghiệm người dùng tốt hơn cho khách hàng.
1. Connections VS Queues
Mỗi cấu hình kết nối trong tập tin cấu hình hàng đợi chứa một thuộc tính hàng đợi (queue). Đây là hàng đợi mặc định mà các công việc sẽ được gửi đến khi chúng được gửi đến một kết nối nhất định. Nói cách khác, nếu bạn gửi một công việc mà không rõ ràng xác định hàng đợi nào nó nên được gửi đến, công việc đó sẽ được đặt vào hàng đợi được xác định trong thuộc tính hàng đợi của cấu hình kết nối.
// This job is sent to the default connection's default queue...
ProcessPodcast::dispatch(); // This job is sent to the default connection's "emails" queue...
ProcessPodcast::dispatch()->onQueue('emails');
2. Database
Để sử dụng database trình điều khiển queue, bạn sẽ cần một bảng cơ sở dữ liệu để chứa các công việc. Bạn có thể chạy các câu lệnh sau
php artisan queue:table
php artisan migrate
Lưu ý: Sử dụng database trình điều khiển bằng cách cập nhật biến trong tệp QUEUE_CONNECTION ứng dụng của bạn .env
QUEUE_CONNECTION=database
3. Creating Jobs
3.1. Generating Job Classes
Theo mặc định, tất cả công việc có thể xếp hàng cho ứng dụng của bạn đều được lưu trữ trong thư mục app/Jobs. Nếu app/Jobs thư mục không tồn tại, nó sẽ được tạo khi bạn chạy lệnh:
php artisan make:job ProcessPodcast
Sau đó class sẽ triển khai Illuminate\Contracts\Queue\ShouldQueue cho Laravel biết rằng công việc nên được đẩy lên hàng đợi để chạy không đồng bộ.
3.2. Class Structure
Job classes chứa một handle được gọi vào hàng đợi để xử lý công việc. Trong ví dụ này, chúng ta gửi một podcast vào hàng đợi để xử lý bằng cách sử dụng job ProcessPodcast
namespace App\Jobs; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; class ProcessPodcast implements ShouldQueue
{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $podcast; /** * Create a new job instance. * * @return void */ public function __construct($podcast) { $this->podcast = $podcast; } /** * Execute the job. * * @return void */ public function handle() { // Xử lý logic xử lý podcast ở đây // Ví dụ: Ghi ra log hoặc xử lý dữ liệu podcast \Log::info('Processing podcast: ' . $this->podcast->id); }
}
4. Dispatching Jobs
Khi bạn đã viết xong Job class của mình, bạn có thể gửi nó bằng cách sử dụng phương thức dispatch của chính công việc đó. Các đối số được truyền cho phương thức dispatch sẽ được trao cho hàm tạo của công việc:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;
use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\Request; class PodcastController extends Controller
{ /** * Store a new podcast. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $podcast = Podcast::create(...); // ... ProcessPodcast::dispatch($podcast); }
}
4.1. Delayed Dispatching
Nếu bạn muốn chỉ định rằng một công việc sẽ không có sẵn ngay lập tức để xử lý, bạn có thể sử dụng phương thức delay này khi gửi công việc. Ví dụ: hãy xác định rằng một công việc sẽ không có sẵn để xử lý cho đến 10 phút sau khi nó được gửi đi:
ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(10));
4.2. Synchronous Dispatching
Nếu bạn muốn gửi công việc ngay lập tức (đồng bộ), bạn có thể sử dụng phương thức dispatchSync này. Khi sử dụng phương pháp này, công việc sẽ không được xếp hàng đợi và sẽ được thực thi ngay trong quy trình hiện tại:
ProcessPodcast::dispatchSync($podcast);
4.3. Job Chaining
Chuỗi công việc cho phép bạn chỉ định danh sách các công việc được xếp hàng đợi sẽ được chạy theo trình tự sau khi công việc chính được thực thi thành công. Nếu một công việc trong chuỗi bị lỗi thì các công việc còn lại sẽ không được thực hiện. Để thực thi chuỗi công việc được xếp hàng đợi, bạn có thể sử dụng phương thức chain được cung cấp bởi BusFacade.
use App\Jobs\OptimizePodcast;
use App\Jobs\ProcessPodcast;
use App\Jobs\ReleasePodcast;
use Illuminate\Support\Facades\Bus; Bus::chain([ new ProcessPodcast, new OptimizePodcast, new ReleasePodcast,
])->dispatch();
4.4. Dispatching To A Particular Queue
Gửi một job cụ thể vào một hàng đợi nhất định thay vì hàng đợi mặc định. Việc này cho phép bạn quản lý và phân loại các công việc theo từng nhóm công việc khác nhau, giúp tăng cường hiệu suất và quản lý trong hệ thống của bạn.
ProcessPodcast::dispatch($podcast)->onQueue('processing');
4.5. Max Attempts
Nếu một trong các job được xếp hàng đợi của bạn gặp lỗi, bạn có thể không muốn nó tiếp tục thử lại vô thời hạn. Do đó, Laravel cung cấp để xác định số lần hoặc thời gian thực hiện một công việc.Một cách tiếp cận để xác định số lần tối đa một công việc có thể được thực hiện là thông qua --tries switch trên dòng lệnh Artisan.
php artisan queue:work --tries=3
Nếu một công việc vượt quá số lần thử tối đa, nó sẽ bị coi là công việc "failed"
5. Running The Queue Worker
Bắt đầu xử lý các công việc trong hàng đợi.
php artisan queue:work
Chỉ định kết nối & hàng đợi
php artisan queue:work redis --queue=emails
Xử lý một số lượng công việc được chỉ định
php artisan queue:work --once
Xử lý số lượng công việc nhất định rồi thoát ra
php artisan queue:work --max-jobs=1000
Xử lý tất cả công việc được xếp hàng đợi và sau đó thoát
php artisan queue:work --stop-when-empty
Xử lý công việc trong một số giây nhất định
php artisan queue:work --max-time=3600
6. Error Handling
Nếu một ngoại lệ được đưa ra trong khi công việc đang được xử lý, công việc sẽ tự động được giải phóng trở lại hàng đợi để có thể thử lại. Công việc sẽ tiếp tục được thực hiện cho đến khi nó được thực hiện với số lần tối đa mà ứng dụng của bạn cho phép. Số lần thử tối đa được xác định bởi --tries switch được sử dụng trên queue:worklệnh Artisan.
Đôi khi bạn có thể muốn đưa một công việc trở lại hàng đợi theo cách thủ công để có thể thử lại sau đó. Bạn có thể thực hiện điều này bằng cách gọi release:
/** * Execute the job. * * @return void */
public function handle()
{ // ... $this->release();
}
Theo mặc định, release sẽ giải phóng công việc trở lại hàng đợi để xử lý ngay lập tức
Tài liệu tham khảo: https://laravel.com/docs/8.x/queues#main-content