fix: replay completed pallet operations
This commit is contained in:
+21
@@ -71,6 +71,9 @@ public class PdaPalletOperationService {
|
|||||||
|
|
||||||
public PalletOperationResponses.Operation assemble(PdaWarehouseIdentity identity,
|
public PalletOperationResponses.Operation assemble(PdaWarehouseIdentity identity,
|
||||||
PalletOperationRequests.Assemble request) {
|
PalletOperationRequests.Assemble request) {
|
||||||
|
PalletOperationResponses.Operation replay = replayIfPresent(identity, "PALLET_ASSEMBLE",
|
||||||
|
request.idempotencyKey(), request);
|
||||||
|
if (replay != null) return replay;
|
||||||
Map<String, PalletPhysicalGateway.PalletReference> pallets = resolvePallets(identity.overseasWarehouseId(),
|
Map<String, PalletPhysicalGateway.PalletReference> pallets = resolvePallets(identity.overseasWarehouseId(),
|
||||||
request.target(), request.sources());
|
request.target(), request.sources());
|
||||||
PalletPhysicalGateway.PalletReference target = pallets.get(code(request.target().palletCode()));
|
PalletPhysicalGateway.PalletReference target = pallets.get(code(request.target().palletCode()));
|
||||||
@@ -85,6 +88,9 @@ public class PdaPalletOperationService {
|
|||||||
|
|
||||||
public PalletOperationResponses.Operation disassemble(PdaWarehouseIdentity identity,
|
public PalletOperationResponses.Operation disassemble(PdaWarehouseIdentity identity,
|
||||||
PalletOperationRequests.Disassemble request) {
|
PalletOperationRequests.Disassemble request) {
|
||||||
|
PalletOperationResponses.Operation replay = replayIfPresent(identity, "PALLET_DISASSEMBLE",
|
||||||
|
request.idempotencyKey(), request);
|
||||||
|
if (replay != null) return replay;
|
||||||
LinkedHashMap<String, PalletOperationRequests.PalletExpectation> expectations = new LinkedHashMap<>();
|
LinkedHashMap<String, PalletOperationRequests.PalletExpectation> expectations = new LinkedHashMap<>();
|
||||||
expectations.put(code(request.source().palletCode()), request.source());
|
expectations.put(code(request.source().palletCode()), request.source());
|
||||||
request.targets().forEach(value -> expectations.put(code(value.target().palletCode()), value.target()));
|
request.targets().forEach(value -> expectations.put(code(value.target().palletCode()), value.target()));
|
||||||
@@ -109,6 +115,9 @@ public class PdaPalletOperationService {
|
|||||||
|
|
||||||
public PalletOperationResponses.Operation swap(PdaWarehouseIdentity identity,
|
public PalletOperationResponses.Operation swap(PdaWarehouseIdentity identity,
|
||||||
PalletOperationRequests.Swap request) {
|
PalletOperationRequests.Swap request) {
|
||||||
|
PalletOperationResponses.Operation replay = replayIfPresent(identity, "PALLET_SWAP",
|
||||||
|
request.idempotencyKey(), request);
|
||||||
|
if (replay != null) return replay;
|
||||||
Map<String, PalletPhysicalGateway.PalletReference> pallets = resolvePallets(identity.overseasWarehouseId(),
|
Map<String, PalletPhysicalGateway.PalletReference> pallets = resolvePallets(identity.overseasWarehouseId(),
|
||||||
request.source(), List.of(request.target()));
|
request.source(), List.of(request.target()));
|
||||||
PalletPhysicalGateway.PalletReference source = pallets.get(code(request.source().palletCode()));
|
PalletPhysicalGateway.PalletReference source = pallets.get(code(request.source().palletCode()));
|
||||||
@@ -129,6 +138,9 @@ public class PdaPalletOperationService {
|
|||||||
|
|
||||||
public PalletOperationResponses.Operation unbind(PdaWarehouseIdentity identity,
|
public PalletOperationResponses.Operation unbind(PdaWarehouseIdentity identity,
|
||||||
PalletOperationRequests.Unbind request) {
|
PalletOperationRequests.Unbind request) {
|
||||||
|
PalletOperationResponses.Operation replay = replayIfPresent(identity, "PALLET_UNBIND",
|
||||||
|
request.idempotencyKey(), request);
|
||||||
|
if (replay != null) return replay;
|
||||||
Map<String, PalletPhysicalGateway.PalletReference> pallets = resolvePallets(identity.overseasWarehouseId(),
|
Map<String, PalletPhysicalGateway.PalletReference> pallets = resolvePallets(identity.overseasWarehouseId(),
|
||||||
List.of(request.source()));
|
List.of(request.source()));
|
||||||
PalletPhysicalGateway.PalletReference source = pallets.get(code(request.source().palletCode()));
|
PalletPhysicalGateway.PalletReference source = pallets.get(code(request.source().palletCode()));
|
||||||
@@ -413,6 +425,15 @@ public class PdaPalletOperationService {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PalletOperationResponses.Operation replayIfPresent(PdaWarehouseIdentity identity, String type,
|
||||||
|
String key, Object request) {
|
||||||
|
String normalizedKey = required(key, "幂等键不能为空");
|
||||||
|
PdaPalletOperation existing = mapper.findOperation(identity.operatorKey(), normalizedKey);
|
||||||
|
if (existing == null) return null;
|
||||||
|
validateExisting(existing, type, hash(request));
|
||||||
|
return read(existing).asReplay();
|
||||||
|
}
|
||||||
|
|
||||||
private void saveTransitions(long operationId, List<PalletPhysicalGateway.Transition> transitions) {
|
private void saveTransitions(long operationId, List<PalletPhysicalGateway.Transition> transitions) {
|
||||||
newTransaction.executeWithoutResult(status -> {
|
newTransaction.executeWithoutResult(status -> {
|
||||||
PdaPalletOperation operation = mapper.selectById(operationId);
|
PdaPalletOperation operation = mapper.selectById(operationId);
|
||||||
|
|||||||
+20
@@ -27,6 +27,7 @@ import org.springframework.transaction.support.DefaultTransactionStatus;
|
|||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
@@ -119,6 +120,25 @@ class PdaPalletOperationServiceTest {
|
|||||||
assertEquals("PDAOPS-LONG-LOCATION-CODE", ledger.getValue().getWarehouseLocationCode());
|
assertEquals("PDAOPS-LONG-LOCATION-CODE", ledger.getValue().getWarehouseLocationCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test void exactReplayReturnsStoredResultBeforeValidatingChangedPalletVersions() throws Exception {
|
||||||
|
var request = new PalletOperationRequests.Swap("idem-replay",
|
||||||
|
new PalletOperationRequests.PalletExpectation("SOURCE", 1),
|
||||||
|
new PalletOperationRequests.PalletExpectation("TARGET", 2), "swap");
|
||||||
|
PdaPalletOperation existing = new PdaPalletOperation(); existing.setId(500L);
|
||||||
|
existing.setOperationType("PALLET_SWAP"); existing.setStatus("COMPLETED");
|
||||||
|
existing.setRequestHash(ReflectionTestUtils.invokeMethod(service, "hash", request));
|
||||||
|
var stored = new com.baiyue.lastleg.palletops.dto.PalletOperationResponses.Operation(
|
||||||
|
500L, "PALLET_SWAP", "idem-replay", "COMPLETED", false, LocalDateTime.now(), List.of());
|
||||||
|
existing.setResultJson(new ObjectMapper().findAndRegisterModules().writeValueAsString(stored));
|
||||||
|
when(mapper.findOperation("7", "idem-replay")).thenReturn(existing);
|
||||||
|
|
||||||
|
var replay = service.swap(identity(), request);
|
||||||
|
|
||||||
|
assertTrue(replay.replayed());
|
||||||
|
assertEquals(500L, replay.operationId());
|
||||||
|
verifyNoInteractions(physical);
|
||||||
|
}
|
||||||
|
|
||||||
private static PdaWarehouseIdentity identity() { return new PdaWarehouseIdentity("7", "picker", 88L); }
|
private static PdaWarehouseIdentity identity() { return new PdaWarehouseIdentity("7", "picker", 88L); }
|
||||||
private static PalletPhysicalGateway.PalletReference pallet(long id, String code, long warehouse, int version) {
|
private static PalletPhysicalGateway.PalletReference pallet(long id, String code, long warehouse, int version) {
|
||||||
return new PalletPhysicalGateway.PalletReference(id, code, warehouse, 1000L + id,
|
return new PalletPhysicalGateway.PalletReference(id, code, warehouse, 1000L + id,
|
||||||
|
|||||||
Reference in New Issue
Block a user