← 모든 글

cron 이 사라진 자리에 들어온 것

cron 14개로 불어난 정산 파이프라인이 이벤트 기반으로 전환됐다. HEDVION이 직접 겪은 실패 원인과 재설계 과정, 지금 바로 써먹을 수 있는 전환 전략을 공유한다.

결제 팀이 cron을 믿었던 시간, 그리고 그 대가

HEDVION의 정산 파이프라인은 cron 4개로 시작했다. 자정에 PG사 원장 데이터를 수집하고, 새벽 1시에 정산 계산을 돌리고, 새벽 2시에 결과를 검증하고, 새벽 3시에 정산 완료 알림을 발송하는 구조였다. 각 단계 사이에 1시간 버퍼를 넣어뒀다. 처음 6개월은 잘 돌아갔다.

문제는 이벤트 시즌이었다. PG사 API 응답이 평소보다 느리거나 처리 건수가 2배로 뛰는 날, 새벽 1시 cron이 트리거되는 시점에 수집 작업이 아직 끝나지 않아 있었다. 계산 작업은 절반짜리 데이터를 조용히 집어들고 완료됐다. 오류가 아니라 잘못된 성공이었다. 이 상황을 발견한 건 정산 담당자가 "숫자가 안 맞는다"고 문의를 준 다음 날 오전 10시였다. 밤새 파이프라인은 정상 종료 상태였다.

cron이 14개가 된 날, 파편화가 시작됐다

6개월 후 cron 스케줄은 14개로 불어났다. PG사별 원장 수집, 환율 데이터 갱신, 세금계산서 상태 동기화, 미정산 건 리마인더, 실패 건 재처리, 파트너사 정산 분리 계산, 주간 정산 리포트 생성까지 — 각각의 cron이 독립적으로 돌고, 의존관계는 시간 간격으로만 표현됐다. A가 늦어지면 B는 빈 데이터를, C는 오래된 상태를 처리했다. 이 사실을 실시간으로 알 방법은 없었다.

더 큰 문제는 실패 처리의 파편화였다. 어떤 작업은 3회 재시도, 어떤 작업은 1회, 어떤 작업은 실패해도 로그만 남기고 그냥 넘어갔다. 알림 채널도 제각각이었다. "어제 새벽 정산이 왜 늦게 완료됐나요?"라는 질문에 답하려면 서버 3곳의 로그를 타임스탬프로 맞춰가며 읽어야 했다. 팀이 작을수록 이 운영 비용은 상대적으로 더 크게 느껴진다. 새벽 장애 대응에 쓴 시간이 기능 개발 시간을 갉아먹기 시작했다.

이벤트 기반 전환 — "시간"을 의존성에서 제거한다

이벤트 기반 전환의 핵심은 단순하다. 시간을 의존성의 단위에서 제거하는 것이다. 각 작업은 완료되면 이벤트를 발행하고, 그 이벤트를 구독하는 다음 작업이 즉시 트리거된다. HEDVION의 정산 파이프라인으로 옮기면 이렇게 된다.

[PG사 원장 수집 완료]
    → 정산 계산 작업 트리거
        → [계산 완료]
            → 검증 작업 트리거
                → [검증 통과]
                    → 정산 완료 알림 발송

이 구조에서는 수집이 평소보다 40분 늦게 끝나도 계산 작업은 정확히 완료 직후에 시작된다. 1시간 버퍼가 사라졌다. 전환 후 자정 시작 기준 정산 완료까지 걸리는 평균 시간이 3시간 20분에서 2시간 10분으로 줄었다. 줄어든 70분의 대부분은 각 단계 사이에 끼워넣었던 버퍼 시간이었다 — 실제 처리에 필요한 시간이 아니라 불확실성을 커버하기 위한 시간. 이벤트 기반으로 가면 그 불확실성 자체가 사라진다.

재시도와 멱등성 — 결제 현장에서 이게 선택이 아닌 이유

이벤트 기반 시스템에서 재시도와 멱등성은 옵션이 아니다. 메시지 큐의 at-least-once 보장, 네트워크 순단, 컨슈머 재시작 — 이 중 하나만 발생해도 같은 이벤트가 두 번 처리될 수 있다. 결제·정산 영역에서 이건 단순한 기술 버그가 아니다. 같은 정산 건이 두 번 처리되면 금액 오류가 생기고, 그건 실제 돈의 문제다. 멱등성 설계 없이 이벤트 기반으로 전환하면 재시도가 오히려 더 큰 리스크를 만든다.

HEDVION 팀의 설계는 두 단계로 구성된다. 첫째, 모든 이벤트에 고유한 event_id를 부여한다. 둘째, 각 작업은 처리 시작 전 해당 event_id가 이미 처리됐는지 확인하고, 중복이면 skip하고 완료 응답을 반환한다. 이 처리 기록은 별도 테이블에 보관한다. 재시도는 지수 백오프로 설정하되, 외부 API 호출이 포함된 작업(PG사 원장 수집, 세금계산서 발급)은 최대 재시도 횟수를 3회로 제한하고 초과 시 수동 처리 큐로 분기한다. 자동화가 실패를 숨기지 않고 드러내도록 설계하는 것 — 이게 작은 팀이 새벽 장애를 인지하는 핵심 조건이다.

cron을 완전히 걷어내지 않은 이유

현재 HEDVION 파이프라인에 남아 있는 cron은 3개다. 매일 오전 9시 환율 데이터 수집, 매일 자정 PG사 원장 수집 시작, 매주 월요일 오전 7시 주간 리포트 생성. 세 작업의 공통점은 이벤트 트리거가 없다는 것이다 — 외부 데이터가 특정 시점에 준비되거나, 비즈니스 리듬 자체가 시간 기반인 경우 cron이 여전히 맞는 도구다.

다만 역할이 달라졌다. 이전의 cron은 파이프라인 전체를 시간으로 통제했다. 지금의 cron은 파이프라인의 시작점(entry point) 역할만 한다. 수집 완료 이벤트가 발행되면 그 이후 흐름은 이벤트 체인이 이어받는다. cron을 완전히 제거하지 않은 건 의도적인 트레이드오프다. 우리가 연동하는 PG사 중 2곳은 아직 webhook 방식을 지원하지 않는다. 현실적인 선에서의 타협 — 이상적인 아키텍처와 지금 운영 가능한 구조 사이의 균형이다.

지금 바로 적용할 수 있는 것들

cron이 5개 이상이고 그 사이에 의존관계가 있다면 오늘 당장 시작할 수 있는 것들이 있다.

1. 의존성 지도를 먼저 그려라. 현재 cron 목록을 나열하고 A → B 의존관계를 화살표로 이어본다. 연결된 노드들이 이벤트 체인으로 전환할 후보다. 독립 노드는 cron으로 남겨도 된다. 이 지도가 없으면 어디서 시작해야 할지 알 수 없다.

2. 실패 처리 정책을 먼저 통일하라. 이벤트 기반 전환 전이라도, 작업마다 다른 재시도 로직을 공통 레이어로 옮기는 것만으로도 운영 부담이 줄어든다. 재시도 횟수, 백오프 전략, 실패 알림 채널을 표준화하라.

3. 멱등성을 먼저 설계하고 이벤트를 붙여라. 순서가 중요하다. 멱등성 없이 이벤트 기반으로 가면 재시도가 오히려 더 큰 문제를 만든다. event_id 기반 중복 처리 방지는 구현 비용이 낮고 효과는 크다.

4. 가장 자주 실패하는 cron 하나부터 바꿔라. 전환은 한 번에 할 필요 없다. 가장 많은 운영 개입이 필요한 작업 하나를 이벤트 기반으로 전환하고 3주 운영해보는 것이 시작이다. 결제·정산 파이프라인은 복잡성이 쌓이는 속도가 빠르다. 구조를 잡는 비용은 팀이 작을 때 가장 싸다.


— by slecs

* 위 링크는 인프런 affiliate 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

📚 추천 강의
한 입 크기로 잘라먹는 바이브코딩 (with Claude Code)
Claude Code로 바이브코딩, 개발자라면 꼭 들어야 할 필수 강의
강의 보러가기 →

* 위 추천 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.