From 93704a24cec462162653f0bc9e747e48a82b52cf Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 8 Sep 2026 23:59:50 +0800 Subject: [PATCH] fix(warehouse-overseas): avoid pallet batch gap lock --- .../warehouse/service/WarehousePalletBatchService.java | 7 ------- .../openapi/warehouse-pallet-batch-internal-v1.yaml | 4 ++-- .../warehouse/schema/WarehousePalletBatchContractTest.java | 1 + .../warehouse/service/WarehousePalletBatchServiceTest.java | 5 +++++ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/WarehousePalletBatchService.java b/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/WarehousePalletBatchService.java index d52a09257..fb26a5cba 100644 --- a/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/WarehousePalletBatchService.java +++ b/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/WarehousePalletBatchService.java @@ -51,13 +51,6 @@ public class WarehousePalletBatchService { public WarehousePalletBatchResponse ensureReserved(WarehousePalletBatchRequests.EnsureReserved request) { WarehousePalletBatchRequests.EnsureReserved normalized = normalize(request); String requestHash = hash(normalized); - WarehousePalletBatchEntity existing = batches.lockByKey(normalized.warehouseId(), normalized.batchKey()); - if (existing != null) { - requireSameRequest(existing, normalized.warehouseId(), requestHash); - if ("COMPENSATED".equals(existing.getStatus())) return reactivate(existing); - return response(existing, items.lockByBatch(existing.getId()), true); - } - WarehousePalletBatchEntity batch = new WarehousePalletBatchEntity(); batch.setId(IdWorker.getId()); batch.setWarehouseId(normalized.warehouseId()); diff --git a/warehouse-overseas-service/src/main/resources/openapi/warehouse-pallet-batch-internal-v1.yaml b/warehouse-overseas-service/src/main/resources/openapi/warehouse-pallet-batch-internal-v1.yaml index c7a6792f2..717b6f3dc 100644 --- a/warehouse-overseas-service/src/main/resources/openapi/warehouse-pallet-batch-internal-v1.yaml +++ b/warehouse-overseas-service/src/main/resources/openapi/warehouse-pallet-batch-internal-v1.yaml @@ -15,7 +15,7 @@ paths: /internal/v1/warehouse-pallet-batches/confirm: post: summary: 确认Lastleg已持久化托盘快照并建立业务绑定 - description: 仅RESERVED可确认;重复确认返回同一结果,不生成新托盘或资源锁。 + description: 仅RESERVED可确认;commandKey幂等作用域为(warehouseId,batchKey,commandKey),无需全局唯一;同作用域同载荷重复确认返回同一结果,不生成新托盘或资源锁。 security: [{ internalServiceToken: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ConfirmRequest' } } } } responses: @@ -23,7 +23,7 @@ paths: /internal/v1/warehouse-pallet-batches/compensate: post: summary: 补偿释放Lastleg本地失败对应的本批未确认资源 - description: 仅RESERVED且尚未建立业务绑定的本批资源可补偿;CONFIRMED或已被后续占用时返回A0409。 + description: 仅RESERVED且尚未建立业务绑定的本批资源可补偿;commandKey幂等作用域为(warehouseId,batchKey,commandKey),无需全局唯一;CONFIRMED、异载荷重放或已被后续占用时返回A0409。 security: [{ internalServiceToken: [] }] requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/CompensateRequest' } } } } responses: diff --git a/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/schema/WarehousePalletBatchContractTest.java b/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/schema/WarehousePalletBatchContractTest.java index 3c4ef6ab7..a2dcdbed7 100644 --- a/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/schema/WarehousePalletBatchContractTest.java +++ b/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/schema/WarehousePalletBatchContractTest.java @@ -33,6 +33,7 @@ class WarehousePalletBatchContractTest { .contains("/internal/v1/warehouse-pallet-batches/confirm:") .contains("/internal/v1/warehouse-pallet-batches/compensate:") .contains("业务冲突仍为HTTP 200且响应体code=A0409") + .contains("commandKey幂等作用域为(warehouseId,batchKey,commandKey),无需全局唯一") .contains("businessKey: { type: string, minLength: 1, maxLength: 100 }") .contains("palletCode: { type: string, maxLength: 64 }") .doesNotContain("'409':"); diff --git a/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/service/WarehousePalletBatchServiceTest.java b/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/service/WarehousePalletBatchServiceTest.java index 292d6abee..59f33897e 100644 --- a/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/service/WarehousePalletBatchServiceTest.java +++ b/warehouse-overseas-service/src/test/java/com/baiyue/warehouse/service/WarehousePalletBatchServiceTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; @@ -74,6 +75,7 @@ class WarehousePalletBatchServiceTest { ArgumentCaptor scope = ArgumentCaptor.forClass(Long.class); verify(resources, times(2)).createPallet(scope.capture(), anyLong(), any(PalletRequests.SaveRequest.class)); assertThat(scope.getAllValues()).containsOnly(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE); + verify(batches, never()).lockByKey(WAREHOUSE, "container-1"); ArgumentCaptor reservations = ArgumentCaptor.forClass(WarehouseResourceLockRequests.ReserveRequest.class); verify(locks, times(2)).reserve(reservations.capture()); @@ -100,6 +102,9 @@ class WarehousePalletBatchServiceTest { assertThat(response.replayed()).isTrue(); assertThat(response.batchId()).isEqualTo(inserted.get().getId()); + InOrder order = org.mockito.Mockito.inOrder(batches); + order.verify(batches).insertIgnore(any()); + order.verify(batches).lockByKey(WAREHOUSE, "container-1"); verify(resources, never()).createPallet(anyLong(), anyLong(), any()); verify(locks, never()).reserve(any()); }