3,143건을 연동 해제해야 했는데 API가 있어서 배치로 돌리기로 하고 500건씩 일곱 청크로 나눠 실행했다.
Table of contents
Open Table of contents
청크마다 되읽은 이유
한꺼번에 안 돌리고 나눈 김에 매 청크마다 DB를 확인하게 했는데, API 응답만 보지 않고 상태값을 직접 세어 대조하는 절차다.
이 확인을 넣는 데 드는 비용은 쿼리 한 줄이었고 안 넣었으면 나중에 전체를 다시 대조해야 했을 것이다.
여섯 번째 청크의 불일치
여섯 번째 청크에서 API는 500건 전부 성공이라고 했는데 DB에는 499건만 바뀌어 있었고 한 건이 그대로 남아 있었다.
그 한 건만 골라 다시 보내니 이번에도 성공이라는 응답이 왔다. DB를 다시 보니 상태가 그대로였고 이번에는 갱신 시각까지 함께 확인했다.
갱신 시각이 가른 것
갱신 시각이 몇 달 전 값 그대로 멈춰 있었다. 처리됐다면 실행 시각으로 갱신됐을 텐데 과거 그대로라는 것은 이 레코드에 손도 안 댔다는 뜻이다.
상태값만 봤으면 조건이 안 맞아 상태가 유지된 것인지 아예 안 건드린 것인지 구분할 수 없었다. 갱신 시각이 그 둘을 갈랐다. API가 어디선가 조용히 건너뛰고 성공 목록에 넣은 것이고 이것을 무음 스킵이라고 부르기로 했다.
API 내부에서 왜 건너뛰었는지는 우리 코드가 아니어서 끝내 확인하지 못했다. 조건이 안 맞아서일 수도 있고 예외를 삼켰을 수도 있는데, 원인은 몰라도 판별 방법만은 확정됐다.
무음 스킵의 분류
재시도해도 같은 결과가 나오는 것을 두 번 확인했으므로 계속 재시도하면 무한 반복이 된다. 그래서 재시도와 재등록 대상에서 빼고 잔여 목록이라는 별도 항목으로 집계했다.
이렇게 나누고 나니 시도한 수가 성공과 무음 스킵의 합으로 정확히 맞아떨어졌다. 무음 스킵을 실패로 세면 재시도가 필요한 1건이 되고 그 재시도가 영원히 안 끝나며, 성공으로 세면 3,143건 성공인데 실제로는 3,142건이다. 별도 항목으로 둬야 검산이 맞는다.
이 패턴을 알고 나서 앞선 큰 실행 기록을 다시 보니 2만 4천여 건짜리 실행에서도 같은 것이 11건 있었다. 그때는 청크별 확인을 안 했거나 했어도 그냥 넘어갔던 것으로 보인다.
청크 확인이 만든 조건
이 발견이 가능했던 조건은 청크마다 사후 확인을 넣었다는 것 하나뿐이었다. 한꺼번에 보내고 마지막에 한 번 확인했으면 3,142와 3,143의 차이를 봐도 어느 건인지 찾기 어려웠을 것이다.
청크가 500건이라 대조할 범위가 좁았고 그래서 한 건을 바로 특정할 수 있었다. 절차로도 정리했는데 청크로 나누고 실행하고 DB를 확인하고 안 맞으면 미반영 건을 특정해 단건 재시도한 뒤 갱신 시각을 보고 안 바뀌면 무음 스킵으로 확정한다. 그리고 마지막에 시도한 수와 성공한 수와 무음 스킵의 수로 검산한다.
정리
- 일괄 API가 처리하지 않은 건도 성공 목록에 담을 수 있다
- 판정은 DB를 되읽어 상태값과 갱신 시각을 함께 본다
- 상태값만 보면 조건 미충족과 미처리를 구분할 수 없다
- 갱신 시각이 과거 그대로면 손도 안 댄 것이다
- 재시도해도 같으면 무음 스킵으로 확정하고 별도 관리한다
- 실패로도 성공으로도 세지 않아야 검산이 맞는다
- 청크로 나누면 미반영 건을 바로 특정할 수 있다
- 패턴이 알려지면 과거 실행에서도 같은 것이 보인다