Idempotent nghĩa là xử lý cùng một message nhiều lần cho kết quả giống hệt xử lý một lần. Cần thiết vì broker giao at-least-once: retry, rebalance, ack rớt đều sinh bản lặp.
Cách làm phổ biến — lưu dấu vết message đã xử lý trong cùng transaction với thay đổi nghiệp vụ:
-- table of consumed message ids, unique index does the deduplication
BEGIN;
INSERT INTO processed_messages (message_id) VALUES ($1); -- violates unique -> already handled
UPDATE accounts SET balance = balance + $2 WHERE id = $3;
COMMIT;Nếu INSERT vi phạm unique thì rollback và ack luôn, coi như đã xử lý.
Chọn dedup key:
- Ưu tiên khoá nghiệp vụ ổn định do producer sinh ra: order_id, payment_id, event_id (UUID gắn vào message lúc tạo).
- Không dùng offset/delivery tag của broker — chúng đổi khi replay hoặc đổi partition.
- Không hash toàn bộ payload nếu payload chứa timestamp gửi, vì retry sẽ ra hash khác.
Một số thao tác vốn đã idempotent (gán trạng thái status = 'paid', UPSERT theo khoá) thì không cần bảng dedup; thao tác cộng dồn (balance + x, tăng counter, gửi email) thì bắt buộc phải có.