# 재개 지점의 계약 81: * @param resumeFrom how many candidates a previous attempt durably moved # 그리고 건너뛰는 자리의 주석 // Everything before resumeFrom was moved and settled by the previous attempt. Re-publishing // it is not a retry, it is a duplicate. for (MessageId messageId : candidates.subList(Math.min(resumeFrom, candidates.size()), candidates.size())) { if (attempt(messageId, request)) { # 그런데 체크포인트가 세는 것은 시도한 개수다 List moved = new ArrayList<>(); int failed = 0; int completed = resumeFrom; moved.add(messageId); } else { failed++; } completed++; checkpoint.accept(completed); } # 그 체크포인트 값이 다음 재개 지점이 된다 return new AdminOperationLease( approvalTicket, planDigest, claimed.operationId(), claimed.leaseOwner(), claimed.leaseToken(), claimed.itemsCompleted()); // Either the previous attempt failed, or its lease expired without a completion. Both resume // from the checkpoint under a new token, which fences the previous holder out. return new AdminOperationRecord( approvalTicket, planDigest, operationId, # 두 저널 구현이 각각 되돌아가지 않게 고정한다 128: Math.max(current.itemsCompleted(), itemsCompleted), JdbcAdminOperationJournal.java:76: SET items_completed = GREATEST(items_completed, ?), # 완료로 닫힌 승인은 다시 인수되지 않는다 if (existing.state() == AdminOperationState.COMPLETED) { throw new MessageAuthorizationException( "APPROVAL_ALREADY_EXECUTED", ("approval %s was already executed to completion at %s; an approval authorises one" # 목록은 매번 다시 조회하고, 확인되지 않은 재발행은 정착시키지 않는다 100: List candidates = source.peek(request.source(), request.batchSize()); *

{@code stillParked} is not simply {@code candidates - moved}. A message stays parked when its * republish did not confirm, and the redrive deliberately leaves it there rather than settling it — * the DLQ-confirm-before-settle rule applies to a redrive exactly as it does to the original * dead-lettering, because a redrive that settles an unconfirmed republish deletes the last copy. # 전부 정산됐는지 묻는 술어가 이미 있다 * Reports whether every candidate was accounted for. * *

An unaccounted message is a bug, not a partial success: it was neither republished nor left * parked, which means the redrive lost track of it. * * @return true when moved plus still-parked covers every candidate */ public boolean isFullyAccounted() { # 그 술어를 부르는 main 코드: 0 # 부르는 테스트 메서드: ApprovedPlanExecutionTest.java:214: assertThat(accounted.isFullyAccounted()).isTrue(); ApprovedPlanExecutionTest.java:215: assertThat(unaccounted.isFullyAccounted()) # 이 경로에는 실행 가능한 구현이 없다 오케스트레이터를 생성하는 코드: 0 RedriveSource 를 구현하는 main 코드: 0 유일한 구현과 그 조회·정착 private static final class RecordingSource implements RedriveService.RedriveSource { private List staged = List.of(); private final List settled = new ArrayList<>(); private void stage(List ids) { staged = List.copyOf(ids); } @Override public List peek(DestinationName destination, int batchSize) { return staged; } @Override public void settle(DestinationName destination, MessageId messageId) { settled.add(messageId); } }