0

Series Laravel Email & Mailtrap #3: Giải phóng Server với Queue (Hàng đợi) – Gửi mail 0 độ trễ

1. Chuẩn bị Database để lưu Hàng đợi

Để Server biết có bao nhiêu email đang chờ được gửi, chúng ta cần một chỗ để ghi nhớ chúng. Mặc định Laravel để QUEUE_CONNECTION=sync (không dùng hàng đợi). Chúng ta sẽ chuyển nó sang dùng Database (hoặc Redis nếu hệ thống lớn, nhưng bài này ta dùng DB cho dễ setup).

Mở file .env và sửa dòng sau:

QUEUE_CONNECTION=database

Tiếp theo, mở Terminal để tạo bảng lưu trữ các "công việc" (jobs) đang chờ và các "công việc bị lỗi" (failed_jobs):

php artisan queue:table
php artisan migrate

Lúc này, trong Database của bạn sẽ xuất hiện bảng jobs.

2. Sửa code: Thay vì "Gửi ngay", hãy "Xếp hàng"

Nhờ kiến trúc của Laravel, việc chuyển từ gửi đồng bộ sang gửi ngầm (Queue) dễ đến mức khó tin. Bạn không cần sửa bất kỳ dòng code nào trong file WelcomeEmail.php hay file welcome.blade.php.

Tất cả những gì bạn cần làm là thay chữ send thành chữ queue.

Hãy mở file routes/web.php (hoặc Controller của bạn) và sửa lại:

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeEmail;
use Illuminate\Support\Str;

Route::get('/test-email', function () {
    $data = [
        'name' => 'Hiếu Nguyễn',
        'station' => 'Ga Bến Thành',
        'price' => 15000,
        'ticket_code' => strtoupper(Str::random(8))
    ];

    // Thay vì dùng ->send(), ta dùng ->queue()
    Mail::to('khachhang_test@gmail.com')->queue(new WelcomeEmail($data));

    return 'Thành công! Yêu cầu gửi email đã được ném vào hàng đợi. Người dùng không phải chờ nữa!';
});

Bây giờ, hãy ra trình duyệt tải lại trang /test-email. Bạn sẽ thấy kết quả trả về ngay lập tức (chưa tới 0.1 giây). Không còn độ trễ 3-4 giây như Bài 2 nữa!

3. Kích hoạt Worker: "Công nhân" gửi mail

Nếu bạn kiểm tra trong Mailtrap lúc này, bạn sẽ không thấy email nào bay tới cả. Tại sao vậy?

Vì hàm ->queue() mới chỉ làm nhiệm vụ ghi một dòng dữ liệu vào bảng jobs trong Database (giống như ghi giấy nhớ). Chúng ta cần một "người công nhân" (Worker) chạy ngầm để đọc bảng jobs này và thực hiện việc gửi email thực sự.

Mở một tab Terminal mới (giữ cho nó chạy liên tục) và gõ lệnh:

php artisan queue:work

Ngay lập tức, bạn sẽ thấy Terminal báo Processing: App\Mail\WelcomeEmail. "Công nhân" đã nhặt công việc lên xử lý. Khi nó báo Processed, hãy kiểm tra Mailtrap, email của bạn đã nằm gọn ở đó!

4. Kỹ thuật nâng cao: Hẹn giờ gửi (Delay Queue)

Sẽ có những kịch bản bạn không muốn gửi email ngay. Ví dụ: Khách hàng mua vé xong, 2 tiếng sau bạn mới muốn gửi email khảo sát dịch vụ. Laravel hỗ trợ hàm later() cực kỳ thanh lịch.

// Gửi email sau 2 tiếng tính từ thời điểm hiện tại
Mail::to('khachhang_test@gmail.com')
    ->later(now()->addHours(2), new WelcomeEmail($data));

"Công nhân" (Worker) sẽ thấy giấy nhớ này trong Database, nhưng nó sẽ phớt lờ cho đến khi đúng 2 tiếng sau mới bắt đầu xử lý.

Tổng kết Bài 3

Chỉ với việc cấu hình QUEUE_CONNECTION và thay đổi từ send() sang queue(), bạn đã loại bỏ hoàn toàn nút thắt cổ chai (bottleneck) về hiệu năng khi gửi email, mang lại trải nghiệm mượt mà nhất cho người dùng của hệ thống AFC. Trên môi trường Production thực tế, lệnh php artisan queue:work sẽ được quản lý bằng công cụ Supervisor (trên Linux) để đảm bảo nó luôn chạy ngầm 24/7.

Đến đây, các bước thiết lập kỹ thuật gửi thư cơ bản đã hoàn thiện. Ở Bài 4 (Trạm cuối), để làm cho giao diện email trở nên thật lộng lẫy trên mọi thiết bị, bạn muốn chúng ta học cách xây dựng Markdown Email (hệ thống component UI email có sẵn của Laravel), hay muốn tìm hiểu cách dùng Event/Listener để tự động kích hoạt việc gửi mail khi có hành động "User đăng ký thành công"?


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí