cron 이 사라진 자리에 들어온 것
단순한 cron 스케줄러를 걷어내고 이벤트 기반 워크플로우로 전환한 과정과, 그 과정에서 배운 것들을 공유한다.
배치 작업을 처음 만들 때 대부분의 팀이 cron 으로 시작한다. 매일 자정에 정산을 돌리고, 매 시간마다 외부 데이터를 동기화하고, 매 5분마다 상태를 체크한다. 간단하고 직관적이다. 그런데 시간이 지나면서 cron 스케줄이 점점 늘어나고, 어느 순간부터 작업들이 서로 의존하는 구조가 생기기 시작한다.
우리 팀도 이 단계를 거쳤다. cron 이 10개를 넘어가면서 관리가 어려워졌다.
cron 의 한계가 드러난 순간들
첫 번째 문제는 의존성이다. A 작업이 끝나야 B 작업을 돌릴 수 있는데, cron 은 시간 기반이라 A 가 얼마나 걸릴지 알 수 없다. 여유를 두고 B 를 늦게 설정하면 전체 파이프라인이 느려지고, 타이트하게 잡으면 A 가 늦게 끝나는 날 B 가 빈 데이터를 처리하게 된다.
두 번째 문제는 실패 처리다. cron 작업이 실패했을 때 재시도 로직을 직접 구현해야 한다. 로그를 남기고, 알림을 보내고, 재시도 횟수를 제한하는 코드가 각 작업마다 따로 들어가기 시작한다.
세 번째는 가시성이다. cron 이 언제 돌았고 얼마나 걸렸으며 무엇을 처리했는지 보려면 로그를 직접 파야 한다. 전체 파이프라인 상태를 한눈에 보는 뷰가 없다.
이벤트 기반으로의 전환
우리가 선택한 방향은 이벤트 기반 워크플로우다. 시간 트리거 대신 이벤트 트리거로 작업을 연결하는 방식이다.
핵심 개념은 단순하다. 각 작업은 완료되면 이벤트를 발행한다. 그 이벤트를 구독하는 다음 작업이 자동으로 실행된다.
[정산 데이터 수집 완료]
→ 정산 계산 작업 시작
→ [계산 완료]
→ 알림 발송 작업 시작
이 구조에서는 A 가 언제 끝나든 B 가 정확히 그 직후에 시작된다. 대기 시간 낭비가 없고, 타이밍 충돌도 없다.
재시도와 멱등성
이벤트 기반으로 바꾸면서 두 가지를 반드시 함께 설계했다.
재시도: 작업이 실패하면 지수 백오프로 재시도한다. 재시도 횟수와 대기 시간은 작업별로 설정한다.
멱등성: 같은 이벤트가 두 번 처리되어도 결과가 달라지지 않아야 한다. 네트워크 문제로 이벤트가 중복 발행될 수 있기 때문이다. 작업에 고유 ID 를 붙이고 처리 여부를 기록해서 중복 처리를 막는다.
아직도 cron 을 쓰는 곳
전부 걷어낸 건 아니다. 진입점이 없는 작업, 즉 아무 이벤트에도 연결되지 않고 순수하게 시간 기반으로 시작해야 하는 경우는 여전히 cron 을 쓴다. 예를 들어 매일 아침 외부 환율 데이터를 가져오는 작업은 이벤트 트리거가 없기 때문에 시간 기반 스케줄이 여전히 맞다.
차이는 그 cron 이 파이프라인의 시작점 역할만 한다는 것이다. 그 이후의 흐름은 이벤트가 이어받는다.
얻은 것
전환 후 가장 크게 달라진 것은 각 작업의 실행 이력과 상태를 추적할 수 있게 됐다는 점이다. 파이프라인이 어디서 막혔는지, 재시도가 몇 번 있었는지, 처리 시간이 평소보다 얼마나 늘었는지를 로그를 파지 않고 확인할 수 있다. 운영 시간이 줄어들었다.
— by slecs