입출금 운영 자동화 시스템 Chronos 개발기 (feat. Temporal)

2025. 11. 28.
엄보현
Blockchain Developer
임이삭
Blockchain Developer

Chronos 개발 배경

가상자산 거래소의 블록체인 백엔드를 운영하다 보면 예상치 못한 순간에 대응해야 할 일들이 생깁니다. 네트워크 이슈나 긴급 노드 점검 등 예기치 못한 이벤트는 언제나 발생할 수 있고, 이때마다 담당자는 즉시 대응해야 합니다.

코빗 역시 마찬가지였습니다. 이 글에서 말씀드릴 Chronos 프로젝트 이전, 저희의 입출금 중단 및 재개 프로세스는 100% 수동으로 이루어졌습니다.

기존 운영 프로세스의 문제점

Chronos 이전의 입출금 중단 및 재개 프로세스는 다음과 같았습니다.

하지만 이 방식은 몇 가지 고질적인 문제를 안고 있었습니다.

  1. 휴먼 에러 리스크
    긴급한 상황이나 피로한 상태에서의 수동 조작은 언제나 실수를 유발할 수 있습니다. 자칫 엉뚱한 자산의 설정을 변경하거나, 값을 잘못 입력하면 큰 장애로 이어집니다.
  2. 24/7 대응 부담
    개발자는 명절, 휴가, 새벽에도 상황 발생 시 즉각 대응해야 했습니다. 이는 팀 전체의 피로도를 증가시키는 원인 중 하나였습니다.
  3. 개발 속도 저하
    개발 리소스를 '새로운 비즈니스 로직 구현'이 아닌 '단순 반복 운영 작업'에 투입하고 있었습니다.

우리의 목표

이러한 문제들을 해결하기 위해 입출금 운영 자동화 시스템 Chronos 개발을 시작했습니다. 목표는 단순히 수동 작업을 코드로 옮기는 것이 아니었습니다.

  1. 휴먼 에러 제거
    사람이 개입하는 순간 실수는 발생합니다. 민감한 작업을 자동화해 설정 오류의 위험을 줄이고자 했습니다.
  2. 24/7 대응 부담 해소
    공지 시간에 맞춰 대기하는 것이 아니라, 몇 시간이든 며칠 뒤든 작업을 정확하게 작업을 예약하고 시스템이 수행하도록 만들어야 했습니다.
  3. 투명한 관리와 모니터링
    누가, 언제, 어떤 작업을 예약했는지, 그리고 그 작업의 상태(대기 중/성공/실패)를 한눈에 파악할 수 있는 UI와 히스토리 관리가 필요했습니다.

하지만 '어떻게' 구현할 것인가? (진짜 과제)

목표는 명확했지만, 구현 방법은 신중한 선택이 필요했습니다. 블록체인 입출금 작업은 그 특성상 다음과 같은 요구사항을 충족해야 했기 때문입니다.

  • 올바른 시간에 실행: 공지된 시간에 맞춰서 실행해야 합니다.
  • 장기간 대기 보장: "3일 뒤 오후 6시" 같은 장기 예약을 걸었을 때, 중간에 Chronos가 재시작되더라도 예약 작업을 잊지 않고 반드시 실행해야 합니다.
  • 신뢰할 수 있는 상태 추적: 현재 어떤 예약이 대기 중인지, 실행 중인지, 실패했는지 상태를 명확히 알 수 있어야 합니다.
  • 동적인 스케줄 관리: 실수로 시간을 잘못 입력했거나 상황이 변했을 때, API를 통해 즉시 예약을 수정하거나 취소할 수 있어야 합니다.

Temporal을 선택한 이유

앞서 정의한 요구사항을 보면, 여러 방식들이 떠오를 것입니다.

1. Cron + Database Polling 방식

Cron이 1분마다 DB를 조회하여 실행할 작업이 있는지 확인하는 방식입니다.
하지만 이 전통적인 방식은 개발자가 '인프라 로직의 늪'에 빠지게 만듭니다.

  • API 호출이 실패한다면? Retry 로직을 직접 구현해야 합니다.
  • 작업 중일 때 서버가 다운되면? Timeout 처리 및 복구 로직을 직접 구현해야 합니다.
  • 여러 인스턴스가 문제된다면? 분산 Lock 등을 직접 구현해야 합니다.

2. 메시지 큐 (Message Queue) 방식

메시지 큐의 지연 전송(Delayed Delivery) 기능을 사용하는 방식입니다. 널리 쓰이는 방식이자, 앞선 방식보다는 훨씬 세련됐죠.
하지만 이 방식은 동적 스케줄 관리에서 치명적인 한계를 드러냅니다.

"오후 3시에 예약된 '중단' 작업을 2시 50분에 급하게 취소해야 한다면?"
"재개 시간을 8시에서 9시로 수정해야 한다면?"

대부분의 큐 시스템에서 이미 발행된 지연 메시지를 찾아 취소하거나 수정하는 것은 구현 난이도가 높아 결국 별도의 DB와 복잡한 보정 로직을 구현해야 합니다.

3. Temporal: "워크플로우 실행과 스케줄링을 모두 보장합니다"

바로 여기에서 Temporal이 완벽한 해답이었습니다.

Temporal은 워크플로우의 '실행 보장'뿐만 아니라 언제 실행할지를 관리하는 '스케줄링' 기능까지 완벽하게 제공합니다.

  • 안정적인 실행: API가 실패해도 워크플로우 내부에서 알아서 재시도합니다.
  • 안정적인 스케줄링: Chronos가 재시작되더라도 (Temporal이 있는 한) 예약된 작업을 안정적으로 관리합니다.
  • 동적 스케줄 관리: 요구사항이었던 API를 통한 예약/조회/수정/취소를 간단한 API 호출로 지원합니다.

큐 방식으로는 복잡했던 '예약 취소'가 Temporal에서는 단 한 줄의 코드로 가능해집니다.

또, 이미 코빗 내 다른 팀들도 Temporal을 이곳저곳에 사용하고 있어 사내 레퍼런스도 충분했습니다.

Chronos 설계 과정

"개발자는 비즈니스 로직에만 집중하고, 인프라 복잡성은 Temporal에게 맡기자"는 원칙으로 설계를 진행했습니다.

1. 비즈니스 프로세스 분석

먼저, 입출금 중단 및 재개 업무를 다음과 같이 단계별로 나누었습니다.

2. Temporal 워크플로우 설계

  1. 단일 워크플로우 vs 다중 워크플로우

모든 로직을 하나의 워크플로우에 넣을 것인지, 역할마다 워크플로우를 분리할 것인지 선택해야 했습니다.

// Option A: 한 곳에 모든 로직 포함 (기각)
func AllInOneWorkflow(ctx workflow.Context, req ScheduleRequest) error {
    // 시간 대기 + 실행 + 검증 + 알림 모두 포함
}
// Option B: 역할별로 분리 (채택)
func ScheduleManagerWorkflow(ctx workflow.Context, req ScheduleRequest) error {
    // Timer → Executor → Validator 순차 실행
}

아래와 같은 이유로 역할마다 워크플로우를 분리하기로 했습니다.

  • 관심사 분리: 각 워크플로우는 단일 책임만 짐
  • 테스트 용이: 각 단계별 독립적 테스트 가능
  • 재사용성: Timer, Executor 등을 다른 용도로 활용 가능
  • 디버깅 편리: 문제 발생 시 특정 단계만 집중 분석
  1. Parent-Child 구조

하나의 워크플로우에 타이머 대기, 실행, 검증, 알림을 모두 포함하거나 타이머 완료 후 다음 워크플로우를 새로 시작하지 않고, Parent-Child 워크플로우 방식을 택했습니다.

func ScheduleManagerWorkflow(ctx workflow.Context, req ScheduleRequest) error {
    // Timer → Executor → Validator 순차 실행
    timerResult, err := executeChildWorkflow(ctx, timerID, ScheduleTimerWorkflow, req)
    executorResult, err := executeChildWorkflow(ctx, executorID, ScheduleExecutorWorkflow, req)
    return executeChildWorkflow(ctx, validatorID, ScheduleValidatorWorkflow, req)
}

Temporal의 Parent-Child 관계는 각 워크플로우가 완전히 독립적인 실행 컨텍스트를 가지면서도, Parent가 모든 Child의 생명주기를 안전하게 관리할 수 있게 해줍니다. 특히 Parent가 취소되거나 실패할 때 모든 Child도 자동으로 정리되게 해 리소스 누수를 방지합니다. 또, 다른 도메인에서 워크플로우를 재사용하는 경우도 고려하여 이 패턴을 선택했습니다.

3. RESTFul API 설계

핵심적인 API 4개는 다음과 같이 설계해 외부에서 쉽게 스케줄을 제어하도록 했습니다.

4. 안전장치 설계

입출금 중단은 고객 자산과 직결되므로 신중해야 합니다. 고객이 입출금을 진행 중일 때 갑자기 이를 중단하면 고객 자산의 입출금이 되지 않거나 처리가 지연될 수 있기 때문입니다.

그래서 단순히 API를 호출하는 것에 그치지 않고, 실제로 설정이 변경되었는지 확인하는 검증 단계를 별도로 두었습니다. 일정 시간 내에 검증이 완료되지 않거나 실패할 경우, 즉시 Slack 알림을 보내는 Fail-safe 로직을 포함했습니다.

결론과 앞으로의 연구 과제

현재 저희 Blockchain Tech 팀은 Chronos를 실제 운영에 적용하고 있습니다. 도입 결과, 다음과 같은 성과를 확인할 수 있었습니다.

  1. 운영 효율성 개선: 자동화를 통해 수동 작업 시간이 단축되었고, 사전 예약 기능을 통해 긴급 대응 업무가 줄어들었습니다.
  2. 안정성 향상: 휴먼 에러로 인한 실수가 사라지고 예약 실행의 정확도가 높아졌습니다.
  3. 개발 생산성 확보: 개발자들이 야간/주말 대기 부담에서 벗어나 핵심 개발 업무에 집중할 수 있게 되었습니다.

앞으로도 입출금 중단 및 재개 예약 기능을 더욱 고도화하고, 현재 수동으로 처리 중인 다른 운영 작업들도 Temporal 기반의 Chronos를 활용해 자동화 범위를 넓혀갈 예정입니다.

  • 예약 관리 개선: 웹 기반 예약 관리 인터페이스 구축
  • 수수료 지갑 관리: 수수료 지갑의 잔고 모니터링 및 자동 충전 구현
  • 통합 모니터링: 노드 상태, 네트워크 수수료 변동 및 주요 업그레이드 내역 실시간 모니터링

저희에게 Chronos는 단순한 자동화 도구가 아니라, 더 안전하고 효율적인 거래소 운영을 위한 기반 시스템으로 발전하고 있습니다. 또, 이 프로젝트를 통해 견고한 워크플로우를 구축함은 물론 개발자가 핵심 비즈니스 로직에 집중할 수 있게 되어 더욱 뜻깊은 프로젝트였다고 생각합니다.

엄보현
Blockchain Developer
코빗에서 블록체인 테크 팀을 맡고 있습니다. 블록체인 인프라와 안정적인 서비스 구조에 관심이 많고, 즐겁게 좋은 기술을 만들어 가고 싶습니다. 반갑습니다!
임이삭
Blockchain Developer
블록체인의 최신 기술들과 트렌드에 관심이 많은 코빗 블록체인 개발자 임이삭입니다. 반갑습니다!