Queue, Retry Và Rate Limiting Cho AI Jobs Chạy Nền Trong Laravel
Giới Thiệu
Nhiều AI task không nên chạy trong request-response cycle. Indexing embeddings, generate summary cho hàng loạt bài viết, hay enrich metadata nên được đẩy sang queue. Nhưng chỉ queue thôi chưa đủ. Nếu không có retry policy và rate limiting, bạn sẽ sớm gặp timeout, duplicate work hoặc bị provider chặn.
Mục lục
- Một AI job cần có gì
- Vì sao nên tách queue riêng cho AI tasks
- Retry, backoff và idempotency
- Monitoring và kịch bản reindex hàng loạt
- Flow background processing hợp lý
- FAQ và các lỗi thiết kế phổ biến
Một Job AI Cần Có Gì?
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class GeneratePostSummary implements ShouldQueue
{
use Queueable;
public int $tries = 5;
public int $backoff = 60;
public function __construct(public int $postId)
{
$this->onQueue('ai');
}
}
Tối thiểu nên có:
- queue riêng cho AI tasks
- số lần retry hữu hạn
- backoff rõ ràng
- idempotency để tránh xử lý lặp
Rate Limiting Không Nên Để Tới Lúc Bị Lỗi Mới Nghĩ
Nếu provider giới hạn RPM hoặc TPM, hãy giới hạn từ phía bạn trước. Điều này đặc biệt quan trọng khi chạy batch jobs sau deploy hoặc reindex toàn bộ nội dung.
Một cách đơn giản là dùng Redis lock hoặc middleware cho job để giới hạn số request đồng thời.
Vì Sao Queue Riêng Cho AI Task Là Hợp Lý
Nếu dùng chung queue với email, webhook, image processing hoặc các job nghiệp vụ quan trọng, AI task có thể làm ảnh hưởng toàn bộ hệ thống khi:
- reindex hàng loạt
- provider bị chậm
- retry tăng mạnh do 429
Tách queue ai giúp bạn:
- scale worker riêng
- theo dõi backlog riêng
- ưu tiên job nghiệp vụ quan trọng hơn nếu cần
Backoff Không Nên Chỉ Là Một Con Số Cố Định
Với lỗi provider, retry sau 60 giây có thể tạm ổn, nhưng trong nhiều hệ thống bạn sẽ muốn:
- exponential backoff
- jitter nhẹ để tránh nhiều job đập lại cùng lúc
- giới hạn thời gian retry tổng thể
Điều này đặc biệt quan trọng với batch jobs lớn, nơi hàng trăm job có thể fail trong cùng một khoảng thời gian.
Retry Cần Phân Loại Lỗi
Không phải lỗi nào cũng nên retry.
- timeout, 429, network issue: nên retry
- prompt invalid, request malformed: không nên retry
- content vượt giới hạn model: nên fail sớm và log
Nếu retry vô điều kiện, bạn chỉ biến lỗi nhanh thành lỗi tốn tiền hơn.
Idempotency Không Chỉ Dành Cho API Public
Nhiều người chỉ nghĩ đến idempotency ở HTTP endpoint. Nhưng với AI jobs, đây là nguyên tắc sống còn. Một job generate summary, create embedding hoặc enrich metadata nếu chạy lặp lại có thể:
- tốn token vô ích
- ghi đè dữ liệu tốt bằng dữ liệu kém hơn
- tạo side effects lặp lại ở downstream system
Giải pháp thường khá đơn giản: check trạng thái hiện tại, prompt version và timestamp trước khi thực hiện.
Idempotency Là Điều Bắt Buộc
Với job AI, hãy luôn tự hỏi: nếu job chạy lại 2 lần thì có sao không?
Ví dụ, trước khi generate summary, bạn có thể kiểm tra xem bài đã có summary với prompt version hiện tại chưa. Nếu có rồi, thoát sớm.
Nên Monitor Điều Gì?
Với queue AI, ít nhất nên theo dõi:
- số job thành công/thất bại
- retry count trung bình
- độ dài queue
ai - latency theo provider
- token usage theo loại job
Nếu không có số liệu này, bạn sẽ chỉ phát hiện vấn đề khi bill tăng hoặc backlog bùng lên.
Một Kịch Bản Dễ Gặp Khi Reindex Hàng Loạt
Bạn publish lại 200 bài và muốn regenerate embeddings. Nếu mỗi bài tạo 10 chunks và mỗi chunk là một request riêng, bạn có thể tạo ra hàng nghìn call trong thời gian ngắn. Nếu không có batching, queue riêng và rate limiting, hệ thống rất dễ gặp:
- spike 429 từ provider
- worker chiếm hết tài nguyên
- job retry chồng lên nhau
Chỉ cần nghĩ trước kịch bản này, bạn sẽ thiết kế pipeline bình tĩnh hơn nhiều.
Những Lỗi Thiết Kế Phổ Biến
- reindex toàn bộ mà không batch hợp lý
- retry mọi lỗi như nhau
- để AI job chạy đồng bộ trong request path vì "tiện"
- không có cơ chế bỏ qua job cũ khi prompt version đã đổi
Một Flow Background Processing Hợp Lý
content updated -> dispatch lightweight indexing job -> chunk content -> batch provider calls -> persist result -> mark version complete
Flow này có hai lợi ích lớn:
- dễ quan sát trạng thái từng bước
- dễ resume hoặc retry từng phần khi có lỗi
Nếu dồn mọi thứ vào một job khổng lồ, bạn sẽ khó biết nó fail ở đâu và retry cũng đắt hơn nhiều.
Khi Nào Nên Hủy Hoặc Bỏ Qua Job Cũ?
Với AI tasks gắn với nội dung, job cũ có thể trở nên vô nghĩa rất nhanh. Ví dụ:
- bài viết đã sửa lại sau khi job được dispatch
- prompt version mới đã được rollout
- user đã trigger lại tác vụ với input mới hơn
Trong các trường hợp này, bỏ qua job cũ thường rẻ hơn và đúng hơn là cứ cố xử lý tiếp.
FAQ
Có nên cho mọi AI task vào queue không?
Không hẳn. Những tác vụ rất nhẹ và không ảnh hưởng trải nghiệm có thể chạy sync. Nhưng phần lớn task gọi model hoặc embeddings đều nên được cân nhắc async trước.
Có nên ưu tiên throughput hay reliability?
Với AI task nền, reliability thường quan trọng hơn throughput. Một pipeline chậm nhưng dự đoán được tốt hơn nhiều so với pipeline nhanh nhưng fail thất thường và tốn tiền do retry.
Có nên gom nhiều item vào một job lớn không?
Cần cân bằng. Job quá nhỏ làm overhead lớn, job quá to làm retry đắt và khó quan sát. Thường nên batch ở mức đủ để giảm overhead nhưng vẫn dễ retry cục bộ.
Key takeaways:
- AI jobs nên được tách khỏi request cycle và thường nên có queue riêng.
- Retry chỉ hữu ích khi được phân loại lỗi đúng và có backoff hợp lý.
- Idempotency là bắt buộc để tránh tốn token và side effects lặp lại.
- Monitoring backlog, retry count, latency và token usage giúp phát hiện vấn đề sớm.
- Với batch lớn, pipeline chia bước nhỏ thường dễ quan sát và rẻ hơn khi retry.
Kết Luận
Queue giúp AI feature không làm chậm request. Retry giúp hệ thống chịu lỗi tốt hơn. Rate limiting giúp bạn không tự DDOS chính provider của mình. Ba thứ này đi cùng nhau. Thiếu một trong ba, tác vụ AI nền rất khó ổn định khi dữ liệu và lưu lượng tăng lên.