fix(firstleg): stop retrying deterministic completion preflight conflicts

This commit is contained in:
2026-10-05 16:05:06 +08:00
parent adaac7aca4
commit 090f57bfb1
2 changed files with 59 additions and 1 deletions
@@ -81,6 +81,57 @@ class LoadingCompletionWorkerTest {
verify(picks).failCompletion(20L);
}
@Test
void completedEventPreflightBusinessFailureIsTerminalOnFirstAttempt() {
LoadingCompletionCommandEntity command = command(0);
when(commands.due(10)).thenReturn(List.of(command));
when(commands.claim(eq(900L), any(String.class), any(LocalDateTime.class))).thenReturn(true);
doThrow(new LoadingPickService.CompletionProcessingException("COMPLETED_EVENT_READY",
new BizException(ResultCode.CONFLICT, "FBA warehouse internal code is missing")))
.when(loadingPicks).processCompletion(eq(command), any(String.class));
when(commands.fail(eq(900L), any(String.class), eq("FAILED"), any(LocalDateTime.class),
eq("COMPLETED_EVENT_READY"), eq(ResultCode.CONFLICT.code()), eq(null), eq(null))).thenReturn(true);
worker.dispatch();
verify(commands).fail(eq(900L), any(String.class), eq("FAILED"), any(LocalDateTime.class),
eq("COMPLETED_EVENT_READY"), eq(ResultCode.CONFLICT.code()), eq(null), eq(null));
verify(picks).failCompletion(20L);
}
@Test
void completedEventPreflightUnexpectedFailureRemainsRetryable() {
LoadingCompletionCommandEntity command = command(0);
when(commands.due(10)).thenReturn(List.of(command));
when(commands.claim(eq(900L), any(String.class), any(LocalDateTime.class))).thenReturn(true);
doThrow(new LoadingPickService.CompletionProcessingException("COMPLETED_EVENT_READY",
new IllegalStateException("temporary database failure")))
.when(loadingPicks).processCompletion(eq(command), any(String.class));
worker.dispatch();
verify(commands).fail(eq(900L), any(String.class), eq("RETRYABLE"), any(LocalDateTime.class),
eq("COMPLETED_EVENT_READY"), eq("S0500"), eq(null), eq(null));
verify(picks, org.mockito.Mockito.never()).failCompletion(org.mockito.ArgumentMatchers.anyLong());
}
@Test
void completedEventPreflightWarehouseUnavailableBusinessFailureRemainsRetryable() {
LoadingCompletionCommandEntity command = command(0);
when(commands.due(10)).thenReturn(List.of(command));
when(commands.claim(eq(900L), any(String.class), any(LocalDateTime.class))).thenReturn(true);
// LoadingPalletLabelService wraps warehouse Feign/circuit-breaker failures in this BizException.
doThrow(new LoadingPickService.CompletionProcessingException("COMPLETED_EVENT_READY",
new BizException(ResultCode.SERVICE_UNAVAILABLE, "warehouse master data temporarily unavailable")))
.when(loadingPicks).processCompletion(eq(command), any(String.class));
worker.dispatch();
verify(commands).fail(eq(900L), any(String.class), eq("RETRYABLE"), any(LocalDateTime.class),
eq("COMPLETED_EVENT_READY"), eq(ResultCode.SERVICE_UNAVAILABLE.code()), eq(null), eq(null));
verify(picks, org.mockito.Mockito.never()).failCompletion(org.mockito.ArgumentMatchers.anyLong());
}
private static LoadingCompletionCommandEntity command(int attemptCount) {
LoadingCompletionCommandEntity command = new LoadingCompletionCommandEntity();
command.setId(900L);