fix(return): replay concurrent merges and extend integrity acceptance
This commit is contained in:
+3
@@ -32,6 +32,9 @@ public interface ReturnInventoryCartonMapper extends BaseMapper<ReturnInventoryC
|
||||
@Select("SELECT * FROM ll_return_inventory_carton WHERE carton_mark=#{cartonMark} LIMIT 1 FOR UPDATE")
|
||||
ReturnInventoryCarton lockMark(@Param("cartonMark") String cartonMark);
|
||||
|
||||
@Select("SELECT * FROM ll_return_inventory_carton WHERE id=#{id} FOR UPDATE")
|
||||
ReturnInventoryCarton lockId(@Param("id") long id);
|
||||
|
||||
@Select("SELECT * FROM ll_return_inventory_carton WHERE source_receipt_id=#{receiptId} LIMIT 1")
|
||||
ReturnInventoryCarton findReceipt(@Param("receiptId") long receiptId);
|
||||
|
||||
|
||||
+3
@@ -10,4 +10,7 @@ import org.apache.ibatis.annotations.Select;
|
||||
public interface ReturnInventoryOperationMapper extends BaseMapper<ReturnInventoryOperation> {
|
||||
@Select("SELECT * FROM ll_return_inventory_operation WHERE operator_id=#{operatorId} AND idempotency_key=#{key} LIMIT 1")
|
||||
ReturnInventoryOperation findKey(@Param("operatorId") String operatorId, @Param("key") String key);
|
||||
|
||||
@Select("SELECT * FROM ll_return_inventory_operation WHERE operator_id=#{operatorId} AND idempotency_key=#{key} LIMIT 1 FOR UPDATE")
|
||||
ReturnInventoryOperation lockKey(@Param("operatorId") String operatorId, @Param("key") String key);
|
||||
}
|
||||
|
||||
+11
-5
@@ -224,7 +224,8 @@ public class ReturnInventoryService {
|
||||
operation.setRequestHash(requestHash); operation.setOperationType("MERGE"); operation.setCreatedAt(now); operation.setUpdatedAt(now);
|
||||
try { operations.insert(operation); }
|
||||
catch (DuplicateKeyException concurrent) {
|
||||
ReturnInventoryOperation existing = operations.findKey(identity.operatorKey(), key);
|
||||
// The duplicate insert waited for the winner; the earlier snapshot cannot see its commit.
|
||||
ReturnInventoryOperation existing = operations.lockKey(identity.operatorKey(), key);
|
||||
if (existing != null) return replayMerge(existing, requestHash);
|
||||
throw concurrent;
|
||||
}
|
||||
@@ -342,14 +343,19 @@ public class ReturnInventoryService {
|
||||
private ReturnInventoryResponses.MergeResult replayMerge(ReturnInventoryOperation operation, String requestHash) {
|
||||
if (!requestHash.equals(operation.getRequestHash())) throw conflict("幂等键已用于不同的合箱请求");
|
||||
if (operation.getResultCartonId() == null) throw conflict("合箱请求正在处理");
|
||||
ReturnInventoryCarton carton = cartons.selectById(operation.getResultCartonId());
|
||||
// The result and its label must also bypass the snapshot established before the insert race.
|
||||
ReturnInventoryCarton carton = cartons.lockId(operation.getResultCartonId());
|
||||
if (carton == null) throw new IllegalStateException("合箱结果箱不存在");
|
||||
List<ReturnInventoryCartonItem> items = cartonItems.listCarton(carton.getId());
|
||||
return new ReturnInventoryResponses.MergeResult(carton.getCartonMark(), items.get(0).getSkuCode(), carton.getTotalQuantity(), label(carton));
|
||||
List<ReturnInventoryCartonItem> items = cartonItems.lockCarton(carton.getId());
|
||||
return new ReturnInventoryResponses.MergeResult(carton.getCartonMark(), items.get(0).getSkuCode(), carton.getTotalQuantity(), label(carton, items));
|
||||
}
|
||||
|
||||
private ReturnInventoryResponses.Label label(ReturnInventoryCarton carton) {
|
||||
List<ReturnInventoryResponses.CartonItem> items = cartonItems.listCarton(carton.getId()).stream()
|
||||
return label(carton, cartonItems.listCarton(carton.getId()));
|
||||
}
|
||||
|
||||
private ReturnInventoryResponses.Label label(ReturnInventoryCarton carton, List<ReturnInventoryCartonItem> cartonLines) {
|
||||
List<ReturnInventoryResponses.CartonItem> items = cartonLines.stream()
|
||||
.map(item -> new ReturnInventoryResponses.CartonItem(item.getSkuCode(), item.getProductNameZh(), item.getQuantity())).toList();
|
||||
return new ReturnInventoryResponses.Label(carton.getCartonMark(), carton.getOverseasWarehouseId(), carton.getCustomerId(),
|
||||
carton.getSourceBatchNo(), carton.getSourceReturnNo(), value(carton.getTotalQuantity()), carton.getLength(), carton.getWidth(), carton.getHeight(), carton.getWeight(), items, LocalDateTime.now(), printableHtml(carton, items));
|
||||
|
||||
Reference in New Issue
Block a user