Skip to content

ADR-0002. Pessimistic Lock SELECT FOR UPDATE trên order khi thay đổi item

TrườngGiá trị
Trạng tháiAccepted
Ngày2026-02-08
Người quyết địnhsale-team
Thay thế

Bối cảnh

  • Hai thiết bị (POS-A và POS-B) thường thêm cùng một item vào cùng order DRAFT cùng lúc.
  • Logic merge tự nhiên — "nếu cùng (orderId, itemType, itemId) đã tồn tại, tăng số lượng" — có race window: cả hai transaction đều thấy không có row, cả hai cùng insert, kết quả là item bị duplicate.
  • Đã được quan sát thấy trong production khi khách gọi "burger × 2" trên tablet A và "burger × 1" trên tablet B cùng lúc — kết quả là hai dòng burger riêng thay vì một dòng qty=3.

Quyết định

Trong SaleOrderService.addSaleOrderItem, service mở một transaction và phát SELECT * FROM "SaleOrder" WHERE id = $1 FOR UPDATE trước khi đọc items và insert/merge. Row order đóng vai trò khóa điều phối cho TẤT CẢ thao tác cấp item trên order đó.

Cùng pattern áp dụng cho:

  • Bulk update item (SaleOrderItemService.update)
  • Clear items (SaleOrderService.clearOrderItems)
  • Checkout (CheckoutService.checkout)
  • Merge / split

Hệ quả

ƯuNhược
Merge race-free: item duplicate gộp deterministicLock giữ đến khi commit transaction — thao tác chậm chặn người khác
Cơ chế duy nhất cho mọi tranh chấp row orderThao tác chỉ đọc không chia sẻ lock (chỉ ghi mới serialize)
Tương thích với mô hình concurrency của PostgreSQLLock waits hiển thị trên metrics DB — có thể có alert false-positive
Không cần mutex cấp ứng dụngTransaction kéo dài gây cascade waits

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

Phương ánƯuNhượcLý do từ chối
Optimistic locking (cột version + retry)DB-portable, không waitsStorm retry khi nhiều thiết bị thêm cùng item; logic client phức tạpSKU hot trong thực tế làm retry tốn kém
Redis lock cấp ứng dụngCross-DBRủi ro stale lock; SPOF; sync overheadTệ hơn primitive DB native
Unique index trên (orderId, itemType, itemId) + ON CONFLICT INCREMENTChỉ DBKhông hoạt động với item CUSTOM (mỗi lần add là dòng unique); không capture được discount cấp dòngKhông phù hợp ngữ nghĩa mode=CUSTOM

Tham chiếu

  • sale/src/services/sale.service.ts (lock pattern trong addSaleOrderItem)
  • sale/src/services/sale-order-item.service.ts (bulk update lock)
  • core/src/models/schemas/sale/sale-item/schema.ts (trường mode)

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