two-thirteen
내구 실행(Durable Execution)과 결정성: 재실행이 안전하려면
내구 실행(Durable Execution)과 결정성: 재실행이 안전하려면
2026-11-09 Engineering Practices

내구 실행(Durable Execution)과 결정성: 재실행이 안전하려면

Lambda Durable Functions 같은 내구 실행이 기대는 원리(이벤트 기록과 재실행)와, 그래서 워크플로 코드가 지켜야 하는 결정성 조건을 Temporal 공식 문서를 따라 정리한 메모입니다.

Lambda Durable Functions 글을 쓰고 나니 질문이 남았습니다. "처음부터 다시 실행하되 끝난 단계는 건너뛴다"는 방식은 어디서 왔고, 무엇을 지켜야 안전한가. 이 분야를 오래 다뤄 온 Temporal의 문서를 읽었습니다.

한 줄 정의

Temporal 문서는 워크플로 실행이 몇 초든 몇 년이든 사실상 한 번, 끝까지 실행된다고 설명합니다. 장애나 중단이 있어도 상태가 남아 있고, 마지막 상태에서 이어서 실행합니다.

이것이 내구 실행입니다. 코드는 평범한 함수처럼 쓰지만, 실행은 죽었다 살아나도 이어집니다.

원리: 기록하고, 다시 돌리며 맞춰 본다

비결은 두 가지입니다.

기록. 실행 중에 일어난 일은 모두 **이벤트 기록(Event History)**에 남습니다.

재실행(Replay). 장애 후 다시 시작할 때, 워커는 워크플로 코드를 처음부터 다시 돌립니다. 그러면서 코드가 내는 명령을 기존 기록과 하나씩 대조합니다. 기록에 이미 있는 일은 다시 하지 않고, 기록의 결과를 씁니다.

Lambda Durable Functions의 "체크포인트와 재실행"과 같은 구조입니다.

그래서 결정성이 필요하다

재실행이 성립하려면 조건이 하나 있습니다. 같은 입력이면 매번 같은 순서로 같은 명령을 내야 합니다. 문서는 워크플로 정의가 결정적이어야 재실행을 지원할 수 있다고 못 박습니다.

어기면 어떻게 될까요. 재실행 때 코드가 낸 명령이 기록과 다르면 실행은 비결정성 오류로 실패합니다.

문서가 피하라고 하는 것들은 이렇습니다.

  • 로컬 시계 시간에 따라 분기하기
  • 난수에 따라 분기하기
  • 실행할 때마다 바뀌는 값에 따라 분기하기

시간이나 난수가 필요하면 SDK가 주는 재실행에 안전한 API를 씁니다. 그 결과가 기록에 남기 때문에 재실행 때도 같은 값이 나옵니다.

바깥세상과의 일은 Activity로

API 호출, DB 조회, LLM 호출처럼 결과가 매번 달라질 수 있는 일은 Activity에 둡니다. 문서에 따르면 Activity는 재실행 경로 밖에서 실행되고 자동으로 재시도됩니다. 재실행 때는 기록된 결과를 쓰니 다시 부르지 않습니다.

Lambda Durable Functions의 context.step()이 이 Activity와 같은 역할입니다.

정리하면

어디에 무엇을
워크플로 코드(재실행됨) 순서와 분기만. 결정적으로
Activity·step(기록됨) 외부 호출, 시간, 난수, LLM 호출

한 가지 덧붙이면, Activity는 재시도되므로 적어도 한 번 실행될 수 있습니다. 결제처럼 두 번 일어나면 안 되는 일은 멱등 키로 한 번 더 막아 두는 게 안전합니다.