Skip to content

ADR-0004. Worker idempotent nhờ tra cứu InventoryTracking

TrườngGiá trị
Trạng tháiAccepted
Ngày2026-02-12
Người quyết địnhPhat Nguyen
Thay thế-

Bối cảnh

  • Mọi Kafka topic đều theo cơ chế at-least-once. Cùng một message có thể được gửi lại khi consumer crash, cân bằng lại phân vùng, hoặc phát lại.
  • InventoryStockRepository.adjustStock không idempotent - áp dụng lại cùng một delta sẽ tính kép.
  • Cần khử trùng lặp theo (saleOrderId, stockId)(purchaseOrderId, stockId) mà vẫn còn hiệu lực sau khi khởi động lại.

Quyết định

Trước mọi thao tác thay đổi tồn kho, worker truy vấn InventoryTracking theo (referenceType, referenceId, inventoryStockId):

  • Nếu đã có dòng → handler dừng sớm, commit Kafka offset, không thay đổi tồn kho.
  • Nếu chưa có dòng → tiếp tục với adjustStock + chèn dòng tracking trong cùng luồng.

InventoryTracking là sổ cái khử trùng lặp. Phần lớn tính idempotent của inventory nằm ở việc đọc từ nó trước khi ghi.

Hệ quả

Ưu điểmNhược điểm
Một cơ chế chung cho mọi worker handlerThêm 1 truy vấn cho mỗi lần thay đổi tồn kho
Dòng tracking đóng vai trò vừa nhật ký kiểm toán vừa khóa khử trùng lặpNếu chèn tracking lỗi sau khi adjustStock thành công, lúc thử lại sẽ trừ kép (hiếm; giảm thiểu nhờ transaction)
Không cần kho lưu trạng thái bên ngoài (Redis, bảng khóa DB)Phải đánh index cho tra cứu tracking để đảm bảo hiệu năng
Công cụ phát lại hoạt động với mọi khoảng thời gian trong quá khứTracking tăng vô hạn - cần phân vùng khi quy mô lớn

Khóa idempotency theo từng topic

TopicKhóa
PAYMENT_SUCCESS(SALE_ORDER, saleOrderId, stockId)
KITCHEN_TICKET_ITEM_STATUS_CHANGED(KITCHEN_TICKET_ITEM, kitchenTicketItemId, materialStockId)
MATERIAL_TRANSFERRED(transferId, fromStockId) + (transferId, toStockId)
Merchant CDCensureDefaultLocation(merchantId) tự idempotent
ProductVariant CDCensureInventoryItem(...) tự idempotent

Phương án thay thế đã cân nhắc

Phương ánƯu điểmNhược điểmLý do từ chối
Bảng IdempotencyKey riêngTách biệt khái niệm rõ ràng hơnThêm một bảng nữa; cùng dữ liệu đã có ở trackingDư thừa
Redis SETEX với TTLTra cứu nhanhMất khi flush Redis; không có dấu vết kiểm toánMong manh; tracking vẫn cần thiết
Chế độ transactional / exactly-once của KafkaPhối hợp DB-KafkaPhức tạp hơn đáng kể; ràng buộc phiên bản brokerQuá mức cho khối lượng công việc của ta

Tham chiếu

  • inventory/src/services/inventory-worker.service.ts (pattern kiểm tra idempotency)
  • inventory/src/services/material-worker.service.ts (cùng pattern cho material)
  • core/src/models/schemas/inventory/inventory-tracking/schema.ts (index khử trùng lặp)

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.