Fail xử lý message. Một phản xạ: “bỏ lại channel để xử lý sau / ai rảnh lấy”. Nghe giống retry — nhưng resend và release không giống nhau, và trên stream shared resend có thể hại app không liên quan.
Demo: 1 group vs 2 group khi resend.
Release vs resend (nhanh)
- Release / requeue / không commit offset: cùng logical message, giữ chỗ trong thứ tự (queue đầu lane / stream offset không tiến). Unrecoverable → block consumer (hoặc partition) + đốt retry.
- Resend: publish lại (thường kèm id gốc) vào channel, đồng thời ack/commit bản đang fail để nhường đường. Unblock flow; có thể mất order; có thể tạo thêm một bản ghi trên stream.
Instant retry trong process (không đụng channel) khác cả hai — an toàn hơn về shared; xem retry.
Single group / queue “của mình”
Một app, một group, channel không ai khác consume độc lập:
- Resend (hoặc delayed resend) hợp write side: 3rd-party sập 2 phút → message quay lại sau, các message khác vẫn chạy.
- Giữ cùng message id / idempotency key để lần sau không double side-effect nếu lần trước thực ra đã gần xong.
- Read/projection: resend xáo order → state machine/view có thể sai; cân nhắc error channel riêng + rebuild/replay có kiểm soát.
Shared: group B không “đăng ký” nhận fail của A
Topic events
group A (billing) — fail message M, resend M' lên topic
group B (analytics) — đã xử lý M lúc offset cũ
→ thấy M' ≈ event mới → xử lý lần 2
A tưởng “chỉ retry cho mình”. B nhận duplicate business event. Trừ khi B idempotent theo đúng id, dashboard/số liệu lệch.
Queue classic ít dính pattern này (một competitive group). Stream + nhiều group = nơi hay bắn chân.
An toàn hơn trên shared
- Instant retry trong consumer A (rollback sạch).
- Error channel / retry queue private chỉ A đọc — delayed backoff ở đó.
- DLQ của A — người review, replay có chủ đích vào handler A, không produce lại shared topic mù.
- Nếu bắt buộc re-publish domain event: event mới với semantics rõ (“retry requested”) + mọi consumer idempotent — không giả vờ là cùng lần emit gốc.
Kafka “resend” hay gặp
- App produce lại payload lên cùng topic = shared-risk ở trên.
- Chỉ seek/rewind offset group A = A đọc lại; B không bị thêm message — gần “release” theo group, không nhân bản cho B.
Hai cơ chế khác nhau: đụng offset group mình vs append log chung.
Checklist trước khi resend
□ Channel có consumer group / app khác không?
□ Write hay read? Order per-key có bị phá có sao không?
□ Message id / idempotency key có ổn định qua resend không?
□ Đã thử instant retry + phân loại transient chưa?
□ Có error channel riêng thay vì shared topic không?
Một câu để nhớ
Resend để unblock single-group write — thường ổn (kèm idempotency). Resend lên shared stream — có thể double mọi group khác.
Khi nghi ngờ: private error path + playbook.