Huny's Dev Blog
huny.dev

Cloudflare Workflows 정식 출시(GA): 서버리스 Durable Execution 원리와 step.waitForEvent 비동기 승인 파이프라인 구축하기

서버리스의 타임아웃 한계를 극복하고 수일·수개월 동안 상태를 보존하는 Cloudflare Workflows의 3계층 아키텍처를 정리한다. step.do, step.sleep, step.waitForEvent 프리미티브와 저널 기반 멱등성 재생 원리, 로컬 Python 검증 및 실무 체크리스트를 살펴본다.

Hun Jang
Hun Jang Nov 9, 2026

Cloudflare Workflows의 서버리스 영속 실행(Durable Execution) 아키텍처를 형상화한 추상 기하학 아트워크다. V8 Isolate가 완전히 동면된 상태에서도 SQLite 저널과 알람 디스패처를 통해 며칠·몇 주간 상태를 유지하고, 비동기 웹훅 이벤트에 반응해 정확히 멈춘 지점부터 재개되는 뫼비우스 순환 파이프라인 개념을 표현했다.

서버리스(Serverless) 컴퓨팅 생태계의 오랜 숙원이었던 '긴 실행 시간'과 '분산 상태 보존' 문제를 근본적으로 해결하는 분기점이 마련되었다. Cloudflare는 서버리스 분산 워커 환경에서 수일, 수 주 동안 상태를 안전하게 보존하며 실행되는 지속 실행 엔진인 **Cloudflare Workflows를 정식 출시(GA)**했다. Cloudflare Blog — Cloudflare Workflows is Generally Available, Cloudflare Docs — Workflows Overview

결론부터 말하면 그동안 서버리스(FaaS) 환경에서 가장 큰 골칫거리였던 Isolate CPU 타임아웃(30초~수분 제한)과 상태 보존의 어려움으로 인해 별도의 외부 메시지 큐(SQS/Kafka), 복잡한 상태 머신(AWS Step Functions), 또는 자체 호스팅 Temporal 클러스터를 운영하던 비효율이 엣지 런타임 차원에서 완전히 해소되었다. 개발자는 복잡한 선언형 YAML 대신 순수 TypeScript 코드로 직관적인 루프와 조건문을 작성하면서 step.do(), step.sleep(), step.waitForEvent() 세 가지 핵심 프리미티브를 통해 분·일·월 단위의 장기 트랜잭션을 zero CPU 비용으로 대기하고, 장애 시 실패한 단계만 선택적으로 지수 백오프 재시도하는 고신뢰 파이프라인을 구축할 수 있다.

이 글은 Cloudflare 공식 기술 블로그와 개발자 문서를 바탕으로 Workflows의 3계층 아키텍처와 이벤트 소싱 기반 저널링 메커니즘을 심층 분석한 실무 엔지니어링 가이드다. 실제 파이프라인 중단 사고를 예방하기 위해 작성한 로컬 Python 시뮬레이션 스크립트로 멱등성 보장, 중간 장애 복구, step.waitForEvent 타임아웃 및 웹훅 재개 라이프사이클을 직접 검증했다.

1. 왜 서버리스에 지속 실행(Durable Execution)이 필요했는가

전통적인 서버리스 아키텍처(Cloudflare Workers, AWS Lambda 등)는 짧은 지연 시간(Low Latency)과 높은 확장성을 제공하지만, 근본적으로 **무상태(Stateless)**와 **엄격한 실행 시간 제한(Timeout)**이라는 두 가지 제약을 안고 있었다.

  • Isolate 수명 주기 제한: 클라우드플레어 워커의 기본 CPU 타임아웃은 수십 밀리초에서 수 분 수준이다. 대규모 데이터 변환, AI 모델 추론 파이프라인, 서드파티 결제 완료 대기, 인간 관리자의 승인(Human-in-the-Loop)처럼 수 시간이나 수 일이 걸리는 작업을 단일 함수 안에서 수행할 수 없다.
  • 파편화된 상태 관리의 복잡성: 긴 작업을 쪼개기 위해 개발자들은 데이터베이스에 수동으로 상태 컬럼(PENDING, PROCESSING, APPROVED)을 두고, Cron 트리거 워커로 주기적으로 DB를 폴링(Polling)하거나 SQS/RabbitMQ 등의 메시지 큐를 엮는 복잡한 인프라를 짜야 했다. 이 과정에서 동시성 충돌, 메시지 중복 처리, 부분 장애 시의 트랜잭션 롤백 등 수많은 분산 시스템 버그가 양산되었다.
  • YAML 기반 Step Functions의 한계: AWS Step Functions 등 기존 오케스트레이션 도구는 상태 머신을 JSON/YAML(Amazon States Language)로 정의해야 하므로 코드 재사용성과 가독성이 떨어지고, 로컬 테스트나 복잡한 알고리즘 표현이 극도로 제한적이었다.

Cloudflare Workflows의 3계층 영속 실행 엔진 아키텍처 다이어그램이다. 최상위 Worker 수신 계층에서 인스턴스를 발급하고, WorkflowEntrypoint의 일반 JS/TS 코드가 step 프리미티브를 실행하며, 최하위 Durable Objects와 임베디드 SQLite 저널이 각 단계의 입출력 결과를 불변 저장하여 결정론적 재생을 보장하는 구조를 도식화했다.

Cloudflare Workflows는 이 문제를 **코드 기반 오케스트레이션(Code-as-Workflows)**과 **엣지 네이티브 영속성(Durable Objects + SQLite)**의 결합으로 풀어냈다.

2. 3대 핵심 프리미티브: step.do, step.sleep, step.waitForEvent

Cloudflare Workflows의 핵심은 WorkflowEntrypoint 클래스의 run(event, step) 진입점이다. 일반적인 함수 실행처럼 보이지만, 주입된 step 객체를 통해 실행되는 모든 동작은 내부적으로 저널(Journal)에 불변 기록된다.

1) step.do() — 실패한 단계만 재시도하는 결정론적 작업

  • 멱등적 메모이제이션(Idempotent Memoization): 콜백 함수가 성공적으로 완료되면 반환된 결과(JSON 직렬화 가능 객체)가 임베디드 SQLite 저널에 영구 기록된다. 워크플로가 이후 단계에서 크래시되거나 재시작되더라도, 이미 완료된 charge-customer 단계는 다시 호출되지 않고 저널에서 저장된 결과를 즉시 반환한다.
  • 스텝별 독립 백오프 재시도: 외부 PG사의 일시적 네트워크 장애나 503 에러 발생 시, 전체 워크플로를 처음부터 다시 시작하는 대신 해당 스텝만 설정된 지수 백오프 정책에 따라 독립적으로 재시도한다.

2) step.sleep() / step.sleepUntil() — 유휴 비용 0원의 장기 대기

  • Isolate 언로드 및 무과금: 일반적인 setTimeout이나 sleep()은 메모리와 Isolate를 점유하여 비용을 유발하지만, step.sleep()은 호출 즉시 워커 Isolate를 메모리에서 언로드(Evict)한다.
  • Cloudflare의 글로벌 알람(Alarms) 인프라에 기상 타이머를 등록해두고, 지정된 시간이 지나면 새로운 Isolate를 할당하여 워크플로를 중단 지점부터 즉시 깨운다.

3) step.waitForEvent() — Human-in-the-Loop 및 비동기 웹훅 네이티브 연동

step.waitForEvent의 이벤트 기반 동면 및 비동기 재개 라이프사이클 다이어그램이다. 결제 후 외부 물류 웹훅이나 승인을 대기하는 동안 V8 Isolate가 메모리에서 완전히 퇴거되어 유휴 비용이 0원으로 유지되고, 이벤트 도착 시 SQLite 저널 상태를 복원하여 미완료 단계부터 정확히 재개되는 무결점 트랜잭션 흐름을 보여준다.

  • 웹훅 인제스천과 라우팅: 외부 시스템(PG사 웹훅, 슬랙 인터랙티브 버튼, 물류 API)에서 이벤트가 들어오면 일반 Worker에서 instance.sendEvent({ name: 'manager.approval_submitted', payload: ... })를 호출한다.
  • Cloudflare의 라우터가 해당 워크플로 인스턴스를 찾아 즉시 깨우고, 전달받은 페이로드를 waitForEvent의 반환값으로 주입하여 다음 스텝으로 매끄럽게 전환한다.
  • 타임아웃 안전망: 지정한 기간(예: 7일) 내에 이벤트가 수신되지 않으면 타임아웃 예외가 발생하므로, 별도의 데드락 방지용 타이머를 만들 필요 없이 즉시 취소 분기로 대응할 수 있다.

3. 기존 오케스트레이션 방식과의 아키텍처 비교

Cloudflare Workflows를 기존의 서버리스 오케스트레이션 방식들과 비교하면 다음과 같다.

구분
1. 기존 Workers + Cron/DB 폴링
2. AWS Step Functions
3. Temporal 자체 호스팅
4. Cloudflare Workflows (GA)
작성 언어 및 패러다임
수동 상태 머신 코드 분할
ASL (JSON / YAML 선언형)
코드 기반 (Go, Java, TS SDK)
순수 TypeScript 코드 (자연스러운 루프·조건문)
대기 중 인프라 비용
Cron 주기별 Isolate 기동 비용
상태 전이 횟수당 과금
Worker 노드 상시 가동 비용
완전한 0원 (Isolate 즉시 언로드)
운영 및 인프라 복잡도
높음 (DB 락, 경합 직접 해결)
보통 (AWS 콘솔 종속성)
매우 높음 (Cassandra/Postgres, 클러스터 유지)
최저 (단일 wrangler 배포, 서버리스 관리형)
장애 복구 메커니즘
수동 재시도 로직 구현 필수
단계별 재시도 지원
이벤트 히스토리 재생 복구
저널 기반 단계별 캐싱 & 실패 스텝 독립 재시도
Human-in-the-Loop
DB 상태값 변경 후 폴링
Task Token 콜백 (복잡)
Signal 메커니즘 지원
네이티브 step.waitForEvent() 지원

4. 로컬 Python으로 검증하는 Durable Execution 멱등성 및 이벤트 대기 엔진

실제 분산 환경에서 저널 기반 멱등성 재생, 실패 단계 독립 재시도, 그리고 step.waitForEvent의 동면 및 타임아웃 메커니즘이 어떻게 동작하는지 재현 가능한 로컬 Python 스크립트로 작성해 검증했다.

직접 실행해 확인한 5가지 검증 시나리오

로컬 터미널 환경에서 위 검증 스크립트(test_cloudflare_workflows_durable_execution.py)를 실행하여 5가지 핵심 케이스가 모두 정상 통과(All 5 Cloudflare Workflows durable execution checks passed successfully!)함을 확인했다.

  1. 멱등적 스텝 메모이제이션 (Case 1): 이전 실행에서 이미 완료된 스텝은 워크플로 재개 시 콜백 함수를 재실행하지 않고 SQLite 저널에서 캐시된 결과를 즉시 반환함을 확인했다(call_counter == 1).
  1. 일시 장애 자동 재시도 (Case 2): 외부 API 호출 실패 시 지정된 max_retries 한도 내에서 지수 백오프로 재시도하여 최종 정상 복구됨을 검증했다.
  1. 비동기 웹훅 이벤트 재개 (Case 3): waitForEvent 대기 상태에서 외부 이벤트 버스를 통해 결제 승인 신호가 주입되었을 때, 대기가 즉시 해제되며 페이로드가 안전하게 후속 단계로 전달됨을 확인했다.
  1. 이벤트 타임아웃 및 폴백 분기 (Case 4): 지정된 시간 내에 이벤트가 도착하지 않았을 때 타임아웃 예외가 정상 발생하고, 즉시 주문 취소/만료 처리 스텝으로 제어권이 넘어감을 검증했다.
  1. 엔드투엔드 장애 복구 라이프사이클 (Case 5): 재고 예약 → 결제 웹훅 대기 → 중간 Isolate 강제 종료 크래시 → 새로운 Isolate에서 재시작 시나리오에서, 이미 완료된 1·2번 단계의 재실행 없이 정확히 3번 슬립 및 4번 배송 이메일 발송 스텝으로 이어져 완주됨을 확인했다.

5. Cloudflare Workflows 실무 도입 체크리스트 및 안티패턴 방지

  1. wrangler.jsonc에 워크플로 바인딩 정의:
  1. 결정론적(Deterministic) 실행 원칙 준수 (필수):
      • step.do 외부에서 Math.random(), Date.now(), UUID 생성 함수를 직접 호출하지 말아야 한다. 워크플로 재생 시 매번 다른 값이 나오면 상태 불일치가 발생할 수 있다.
      • 모든 비결정론적(Non-deterministic) 연산이나 외부 API 호출은 반드시 step.do() 내부로 감싸서 결과값이 저널에 고정되도록 해야 한다.
  1. 스텝 반환값 페이로드 용량 제한 고려:
      • step.do()의 반환값은 SQLite 저널에 직렬화되어 저장되므로 1MB 이하의 메타데이터 위주로 유지해야 한다.
      • 대용량 파일이나 수십 MB 단위의 데이터셋은 Cloudflare R2 버킷이나 D1 데이터베이스에 저장하고, 워크플로 간에는 R2 Key나 D1 ID만 전달하는 것이 정석이다.
  1. waitForEvent 타임아웃 및 사가 패턴(Saga Pattern) 구성:
      • 외부 웹훅을 기다릴 때는 반드시 합리적인 timeout을 지정하고, 타임아웃 발생 시 이미 결제된 금액을 환불하거나 재고 예약을 해제하는 보상 트랜잭션(Compensating Transaction)을 명시해야 한다.
  1. 대시보드 시각적 트레이싱 및 상태 모니터링:
      • Cloudflare 대시보드의 Workflows 탭에서 AST 기반으로 자동 생성된 시각적 흐름도를 확인하고, 인스턴스별 실행 로그, 현재 대기 중인 waitForEvent 상태, 재시도 횟수를 실시간으로 추적할 수 있다.

참고 자료

확인 기준일: November 9, 2026

추천 글