Sau queue vs stream (channel làm được gì), hỏi tiếp: channel dùng để làm gì? Cùng một Kafka topic, recovery “đúng” cho payment worker có thể phá projection — và ngược lại.
Ba purpose: write, read, shared. Demo: Đổi purpose → strategy hợp / không hợp.
Write side — business phải chạy
Channel kích hoạt hành động: trừ tiền, gửi mail welcome, mở ticket 3rd-party, bước workflow… Message = “hãy làm việc này”.
- Ưu tiên: hoàn thành action, continuity. Một payment fail tạm không nên đóng băng mọi payment sau trên cùng lane nếu business không yêu cầu.
- Order tuyệt đối thường không phải requirement toàn cục — hoặc chỉ per aggregate (account id) qua partition key.
- Fail strategy hay gặp: instant retry → delayed resend / error queue → DLQ — nhằm unblock + tự heal transient.
Viết tắt: write side dừng channel = dừng một phần business.
Read side — dựng view từ lịch sử
Projection, search index, analytics, sync read model: “xảy ra gì thì phản ánh vào view”.
- Ưu tiên: đủ event + thứ tự có nghĩa (thường per-key). Skip / ignore bừa = view sai hoặc thiếu, không chỉ “chậm”.
- Fail / block projection: user thấy data cũ — stale — business write vẫn chạy được. Đó là trade-off chấp nhận được hơn corrupt view.
- Strategy: instant retry OK; release/rewind giữ order; cẩn thận resend phá order; ignore gần như cấm nếu view phải đúng.
Viết tắt: read side chậm được, sai không được (trong phạm vi consistency bạn đã hứa).
Shared — nhiều group / app cùng channel
Stream với ≥2 consumer group (billing + analytics + audit…), hoặc bất kỳ setup nào message được consume độc lập nhiều lần theo group.
- App A fail ≠ app B fail. B có thể đã xử lý xong.
- Resend message gốc vào channel → B có thể nhận lần hai (trừ khi mọi consumer idempotent tuyệt đối).
- An toàn hơn: error channel / DLQ riêng group A, không đụng shared log theo kiểu nhân bản event cho cả thế giới.
Chi tiết: resend single-group vs shared.
Ma trận purpose × ưu tiên
Unblock flow Giữ order/đủ event Đừng double app khác
Write ★★★ ★ ★★ (nếu shared)
Read ★ ★★★ ★★
Shared ★★ ★ ★★★
★★★ = constraint cứng. Strategy nào đụng ★★★ là “sai purpose”.
Ví dụ chọn nhanh
-
orders.commands/ queue worker “charge card” → write, single app → delayed retry + DLQ, resend OK hơn là release mãi một poison. -
orders.events→ projection balance → read → đừng ignore; poison thì park + alert, cân nhắc không xáo order per account. -
Topic dùng chung CRM + warehouse → shared → fail CRM không
producelại same event lên topic chung.
Queue “không shared” mặc định
Classic queue thường hành xử như một message group: ai lấy thì của người đó. Shared theo nghĩa nhiều app độc lập ít gặp hơn stream — trừ khi bạn fan-out exchange → nhiều queue (mỗi app một queue = không còn một channel shared, mà nhiều subscription).
Một câu để nhớ
Write: đừng chặn business. Read: đừng làm view sai. Shared: đừng recovery theo cách nhân bản cho hàng xóm.
Purpose × loại channel → mở playbook.