주문-결제-재고-배송처럼 여러 시스템이 엮인 플로우는, “성공"보다 “실패를 어떻게 복구하느냐"가 품질을 결정합니다.
문제는 대부분의 팀이 이 과정을 API 체인 + DB 상태 컬럼 + 수동 재처리 스크립트로 붙여놓고 운영한다는 점입니다. 초반에는 빠르지만, 트래픽이 오르면 재시도 폭증·중복 처리·장애 추적 불가가 같이 옵니다.
Temporal 같은 워크플로 오케스트레이션 엔진은 이 문제를 “비즈니스 순서"와 “실행 복구"를 분리해서 다룹니다. 핵심은 마법 도구가 아니라, 장기 실행 프로세스를 코드로 명시하고 재실행 가능하게 만드는 운영 방식입니다.
이 글에서 얻는 것
- Temporal 도입이 필요한 상황과, 굳이 도입하지 않아도 되는 상황을 숫자 기준으로 구분할 수 있습니다.
- Workflow/Activity/Task Queue/History를 실무에서 어떻게 나누는지 이해할 수 있습니다.
- 재시도·타임아웃·보상 트랜잭션·버전 업그레이드를 운영 가능한 형태로 설계하는 기준을 얻습니다.
핵심 개념/이슈
1) 왜 “DB 상태 + 크론 재처리"가 한계에 부딪히는가
초기에는 orders.status 컬럼 하나로도 돌아갑니다. 하지만 아래 조건이 겹치면 급격히 불안정해집니다.
- 외부 의존 시스템 3개 이상(결제, 쿠폰, 물류, 알림)
- 플로우 총 소요시간이 수십 초~수시간
- 실패 시 사람이 개입해 수동 정리가 필요한 단계 존재
이때는 “어디서 실패했는지"보다 “어디까지 완료됐는지"를 잃기 쉽습니다. 결국 장애 원인 분석보다 정산/환불 정합성 맞추는 데 시간이 더 들어갑니다.
2) Temporal의 기본 모델: 순서(Workflow)와 실행(Activity) 분리
- Workflow: 비즈니스 절차의 상태 머신(순서/분기/보상 규칙)
- Activity: 실제 외부 작업(DB 쓰기, 결제 API 호출, 메시지 발행)
- Task Queue: 워커에게 작업을 분배하는 큐
- History: 워크플로 실행 이력을 이벤트로 저장
실무에서 중요한 점은, Workflow 코드가 “재실행되어도 동일 결과"를 보장해야 한다는 것입니다. 즉 난수, 현재 시각, 외부 API 직접 호출을 Workflow 안에서 막고 Activity로 분리해야 합니다. 이 규칙을 깨면 배포 이후 재현 불가능한 버그가 생깁니다.
3) 재시도/타임아웃/보상은 기본값이 아니라 설계 대상
Temporal을 붙여도 정책이 약하면 사고는 그대로 납니다. 최소한 아래 세 가지는 팀 표준으로 고정하는 편이 안전합니다.
- Activity별 타임아웃:
startToClose,scheduleToClose명시 - 재시도 정책: 최대 횟수, backoff, 비재시도 예외 코드 정의
- 보상 트랜잭션: 실패 시 “되돌릴 단계"를 Workflow에 명시
관련 기반은 멱등성 설계, 재시도·타임아웃·백오프, Outbox/Saga 패턴을 같이 보는 게 좋습니다.
4) 도입 판단 기준(간단 매트릭스)
| 조건 | 권장 접근 |
|---|---|
| 단일 DB 트랜잭션으로 끝남, 1초 이내 | 기존 서비스 코드 + 트랜잭션 유지 |
| 외부 시스템 2~3개, 실패 시 수동 재처리 가끔 발생 | 경량 Saga/Outbox부터 적용 |
| 외부 시스템 3개 이상, 플로우 30초 이상, 재처리 빈번 | Temporal 도입 우선 검토 |
| 사람 승인/대기(분~일 단위) 포함 | Temporal 도입 강력 권장 |
의사결정 우선순위는 보통 정합성 > 복구 시간(MTTR) > 개발 속도 순서로 두는 게 현실적입니다.
실무 적용
1) 첫 파일럿은 “매출 영향 크고 단계가 명확한 플로우"로
처음부터 전 도메인에 확대하면 실패 확률이 높습니다. 아래 조건을 만족하는 1개 플로우로 시작하세요.
- 월 처리량 1만 건 이상
- 실패 시 금전/신뢰 손실이 큰 업무(결제, 환불, 정산)
- 단계가 5~12개로 명확히 분리 가능
예: 주문 승인 플로우
- 재고 예약
- 결제 승인
- 배송 생성
- 알림 발송
- 실패 시 결제 취소/재고 복구
2) 운영 지표는 “성공률” 하나로 끝내면 안 된다
최소 관측 지표를 이렇게 고정해두면 운영 품질이 올라갑니다.
- Workflow 완료율(24h)
- Workflow p95 소요시간
- Activity 재시도 횟수 상위 10개
- Dead letter/수동 개입 건수
- 보상 트랜잭션 실행 비율
실무 임계치 예시:
- 완료율 99.5% 미만 2일 연속: 배포 동결 후 원인 분석
- Activity 재시도 평균 3회 초과: 외부 API 계약/타임아웃 재조정
- 수동 개입률 1% 초과: 워크플로 설계 누락(보상/분기) 우선 수정
3) 버전 업그레이드 전략: “코드 배포"와 “워크플로 호환성” 분리
장기 실행 워크플로가 있을 때는, 단순 롤링 배포만으로 안전하지 않습니다. 구버전 워크플로 인스턴스가 아직 살아있기 때문입니다.
- Workflow 변경 시 version marker(혹은 패치 분기)로 경로 호환성 유지
- 최소 1개 배포 주기 동안 구/신 로직 공존
- 스키마 변경은 Expand/Contract 방식으로 분리
이 원칙을 무시하면 “새 코드 + 옛 실행 이력” 조합에서 예측 불가 오류가 발생합니다.
4) 기존 시스템과 연결: 이벤트 발행은 Outbox로 고정
Workflow 안에서 바로 메시지 브로커에 발행하면, DB 커밋과 이벤트 발행의 원자성이 깨질 수 있습니다. 가능하면 Outbox 테이블 + CDC 또는 안정적 발행 패턴으로 고정하세요. 배경 개념은 Transactional Outbox + CDC를 참고하면 좋습니다.
트레이드오프/주의점
학습비용이 분명히 있다
워크플로 결정론 제약, 리플레이 개념, 버전 관리까지 익혀야 해서 초기 2~4주는 생산성이 떨어질 수 있습니다.단순 CRUD 서비스에는 과한 선택일 수 있다
한 번 호출하고 바로 끝나는 API까지 오케스트레이션으로 감싸면 운영 복잡도만 증가합니다.히스토리/큐 운영이 새 부담이 된다
보존 정책, 워커 스케일링, 장애 시 리드니스 전략을 별도로 설계해야 합니다.보상 트랜잭션은 공짜가 아니다
결제 취소는 가능해도 쿠폰 복원, 포인트 정정, 외부 파트너 연동 정리는 도메인별 정책이 필요합니다.
체크리스트 또는 연습
도입 전 체크리스트
- 대상 플로우의 단계/실패 시나리오를 표로 정리했다.
- Activity별 타임아웃/재시도/비재시도 예외를 문서화했다.
- 멱등키 정책(요청 키, 기간, 저장 위치)을 정했다.
- 보상 트랜잭션 우선순위(금전 정합성 > 사용자 알림 > 분석 로그)를 합의했다.
- 완료율/재시도/수동개입률 대시보드와 경보 기준을 정했다.
연습 과제
- 현재 운영 중인 “주문→결제→배송” 흐름을 Workflow/Activity로 분해하고, 실패 지점을 5개 이상 정의해보세요.
- 결제 API 5xx가 10분간 증가하는 상황을 가정해 재시도 정책(backoff, 상한, circuit-open 조건)을 수치로 작성해보세요.
- 수동 재처리율을 현재 대비 50% 줄이기 위해 어떤 단계를 자동 보상으로 전환할지 우선순위를 세워보세요.
💬 댓글