본문으로 건너뛰기
뒤로

정기 실행이 겹치면 어떻게 할까

초안아직 소유자가 검토하고 실습해 확인하지 않은 글입니다. 학습 기록이 아니라, 확인 전의 글입니다.

읽기 약 5분 · 실습 시간 별도

매분 변환 대기 문서를 찾아 처리하는 Workflow를 시작한다고 하자. 한 번의 처리가 90초 걸리면 다음 시작 시각이 왔을 때 이전 실행이 아직 남아 있다. “매분 실행”이라는 설정만으로 두 실행이 겹쳐도 되는지, 다음 실행을 건너뛸지, 기다릴지는 정해지지 않는다.

Temporal Schedules는 반복 시작과 그 정책을 관리한다. Workflow 안에서 Timer로 대기하는 것과는 목적이 다르다. Timer는 한 실행 안의 대기를 표현하고 Schedule은 정해진 조건에 따라 Workflow 실행을 시작한다.

주기보다 겹침 정책이 업무 의미를 정한다

가상 문서 처리에서 각 정기 실행이 “현재 처리할 문서 목록”을 다시 조회한다면 실행이 겹칠 때 같은 문서를 두 번 가져올 수 있다. 반대로 특정 시간 구간의 요청을 처리한다면 실행을 건너뛰면 그 구간을 놓칠 수 있다. 어떤 데이터를 처리하는지에 따라 적절한 정책이 달라진다.

Schedule의 Overlap Policy는 이전 실행이 남아 있을 때 새 시작을 어떻게 다룰지 정한다. 기본 Skip은 새 시작을 건너뛴다. BufferOne은 대기 하나를 유지하고 이전 실행 뒤 시작한다. BufferAll은 정책과 제한 범위에서 시작할 항목들을 순서대로 기다리게 한다.

AllowAll은 겹치는 실행을 허용한다. CancelOther는 기존 실행의 취소 완료를 기다린 뒤 새 실행을 시작하고, TerminateOther는 기존 실행을 강제 종료한다. 특히 마지막 두 방식은 이미 예약한 허용량과 생성된 결과를 어떻게 정리할지까지 함께 검토해야 한다.

한 정책으로 모든 정기 작업을 설명하지 않는다

최신 상태만 보면 되는 작업은 일부 시점을 건너뛰어도 괜찮을 수 있다. 하지만 시간 구간별 업무를 빠짐없이 처리해야 한다면 Skip만으로 충분하지 않을 수 있다. 이 경우 구간을 입력으로 명시하거나 누락 구간을 별도로 확인하는 설계가 필요하다.

BufferAll도 항상 안전한 선택은 아니다. 평균 처리 시간이 실행 간격보다 길면 대기 작업이 계속 쌓일 수 있다. 놓치지 않았다는 사실과 제시간에 처리했다는 사실은 다르다. 업무가 허용하는 지연과 누적량을 함께 봐야 한다.

AllowAll을 사용하면 빨라질 수 있지만 허용량 예약과 결과 저장의 동시성 조건이 중요해진다. Schedule이 중복 업무 효과를 자동으로 막아 주는 것은 아니다. 개별 문서의 업무 키와 예약 서비스의 원자적 처리 계약을 유지해야 한다.

실행 시간을 주기보다 길게 만든다

대표 실패 실험은 가짜 문서 처리 시간을 Schedule 간격보다 길게 두는 것이다. 먼저 Skip으로 시작 목록을 관찰하고, 같은 조건에서 BufferOne으로 비교한다. 너무 많은 정책을 한 번에 바꾸지 않으면 차이를 설명하기 쉽다.

예상은 Skip에서 이전 실행이 남아 있는 시점의 새 시작이 생략되고, BufferOne에서는 대기 하나가 이전 실행 뒤 시작하는 것이다. 실제 시작 수와 시각은 실행 목록으로 확인한다. 처리 결과 행 수만으로 어느 정책이 적용됐는지 판단하지 않는다.

그다음 선택적으로 AllowAll을 사용해 겹친 실행을 만든다. 두 실행이 같은 문서를 가져갔을 때 예약과 저장이 안전한지 확인한다. 의도한 실패는 “두 Workflow가 존재한다” 자체가 아니라 그로 인해 업무 조건이 깨지는 경우다.

Schedule 일시정지는 실행 중단이 아니다

Schedule을 pause하면 앞으로의 자동 시작을 멈춘다. 이미 시작된 Workflow를 자동으로 취소하거나 멈추는 기능으로 해석하면 안 된다. 배포 중 새 업무 유입만 잠시 중단할 것인지, 기존 실행도 정리할 것인지 별도로 결정한다.

Backfill은 과거 구간에 해당하는 실행을 나중에 시작하는 데 사용할 수 있다. 그러나 결과가 이미 일부 생성됐거나 같은 구간을 수동 실행했다면 중복 처리 문제가 남는다. 재실행 구간과 업무 키를 대조한 뒤 수행해야 한다.

Service가 일시적으로 요청을 처리하지 못한 뒤 얼마나 늦은 실행까지 시작할지도 Catchup Window와 관련된다. 설정의 기본값을 업무 정책으로 그대로 받아들이기보다 “얼마나 늦어도 여전히 의미 있는가”를 정해야 한다. 수동 trigger와 backfill이 동일한 제한을 받는다고 가정하지 않는다.

시간대도 입력의 일부다

매일 특정 시각을 의미하는 Schedule에서는 시간대를 명확하게 적는다. 서버 운영체제의 시간대를 바꾸면 업무 의미도 자동으로 맞아질 것이라고 기대하지 않는다. 지역 시간과 UTC 중 어떤 기준을 사용하고, 날짜 경계의 문서를 어떻게 나눌지 정한다.

공식 Java 문서는 기존 Cron 옵션보다 Schedules 사용을 권한다. 하지만 새 API를 썼다는 사실보다 pause·update·overlap·누락 처리의 의미를 운영자가 설명할 수 있는지가 중요하다. 실습 결과에는 정책과 실행 시각뿐 아니라 각 실행이 처리한 업무 구간을 함께 남긴다.

확인 질문: 매 실행이 현재 미처리 문서를 조회한다면 Skip이 업무 누락으로 이어지는 조건은 무엇일까? Schedule을 pause했는데 변환이 계속되는 것은 왜 정상일 수 있을까?

참고 자료



댓글