체크포인트와 롤백(Checkpoints and Rollback)
모든 그래프 상태 전이(graph-state transition)는 지속화(persist)됩니다. 워커(worker)가 충돌(crash)하면 임대(lease)가 만료되고 다른 워커가 가장 최신의 체크포인트(checkpoint)에서 작업을 이어받습니다. Cloudflare Durable Objects는 몇 시간에서 몇 주에 걸쳐 상태를 유지합니다. 제안 후 커밋(propose-then-commit)(Lesson 15)은 행동마다 롤백 계획(rollback plan)을 정의합니다. 사후 검증(post-action verification)이 그 흐름의 마지막 고리를 닫습니다. EU AI 법(EU AI Act) 제14조(Article 14)는 고위험 시스템(high-risk system)에 대해 실효적인 사람 감독(effective human oversight)을 의무화합니다. 실무적으로 이 말은 체크포인트가 조회 가능(queryable)해야 하고, 롤백이 미리 리허설(rehearsal)되어 있어야 하며, 감사 추적(audit trail)이 배포(deploy)를 견뎌야 한다는 뜻입니다. 가장 날카로운 실패 양상(failure mode)은 이것입니다. 멱등성 키(idempotency key)와 사전 조건 검사(precondition check)가 없으면, 일시적 장애(transient failure) 뒤의 재시도(retry) 한 번이 이미 승인된 행동을 두 번 실행해 버릴 수 있습니다. 사후 검증이 바로 이런 사고를 잡아냅니다.
유형: Learn
언어: Python (stdlib, checkpoint and rollback state machine)
선수 지식: Phase 15 · 12 (지속 실행, Durable execution), Phase 15 · 15 (제안 후 커밋, Propose-then-commit)
예상 시간: 약 60분
문제
지속 실행(durable execution)(Lesson 12)은 충돌한 에이전트(agent)를 다시 이어서 실행할 수 있게 만들어 줍니다. 제안 후 커밋(Lesson 15)은 승인된 행동(action)을 감사 가능한 형태로 남깁니다. 이 강의는 이 둘을 하나로 연결합니다. 승인된 행동이 부분적으로만 실행된 채로 충돌했다가 다시 이어서 실행될 때 어떤 일이 벌어질까요? 롤백은 언제, 어떤 상태(state)를 기준으로 실행되어야 할까요?
실제 시스템들은 이 문제를 서로 다른 방식으로 풀어냅니다.
- LangGraph는 모든 그래프 상태 전이를 PostgreSQL에 체크포인트로 기록합니다. 워커가 충돌하면 임대가 풀리고, 다른 워커가 가장 최신의 체크포인트에서 실행을 재개(resume)합니다. 워크플로(workflow)는
interrupt()에서 일시 정지(pause)하며, 이 인터럽트 자체도 지속화됩니다.
- Cloudflare Durable Objects는 키별 상태(per-key state)를 몇 시간에서 몇 주 동안 보관합니다. 승인된 행동의 연산(computation)과 저장소(storage)를 같은 곳에 배치(co-locate)합니다.
- Microsoft Agent Framework는 워크플로 API에서
Checkpoint 원시 자료형(primitive)을 노출합니다. 재생(replay)과 멱등성(idempotency)의 조합이 재시도를 안전하게 감쌉니다.
어느 경우든 실제로 잘 동작하는 조합은 항상 같습니다. 멱등성 키(중복 실행 방지) + 사전 조건 검사(승인 당시 상태와 여전히 일치하는지 확인) + 사후 검증(부수 효과가 실제로 일어났는지 확인) + 검증 실패 시 롤백입니다.
개념
모든 전이는 지속화된다
그래프 상태 전이란 워크플로가 어떤 이름 붙은 상태(named state)에서 다른 이름 붙은 상태로 옮겨가는 모든 단계를 가리킵니다. 단순한 구현은 특정 커밋 지점(commit point)에서만 상태를 지속화합니다. 반면 프로덕션(production) 수준의 구현은 모든 전이를 지속화합니다. 추가 쓰기 몇 번이라는 비용은, 어디서든 재생이 가능해지고 임대 회복(lease recovery)이 정밀해진다는 신뢰성 이득(reliability gain)에 비하면 작습니다.
임대 회복(Lease recovery)
워커가 충돌해도 워크플로 자체는 사라지지 않습니다. 단지 임대, 즉 "이 워커가 이 실행을 맡고 있다"는 짧은 권리 주장(claim)이 만료될 뿐입니다. 다른 워커가 가장 최신의 체크포인트를 집어 들고 실행을 이어받습니다. 이 임대 메커니즘 덕분에 프로덕션 시스템은 진행 중인 작업(in-flight work)을 잃지 않고 순차적 배포(rolling deploy)를 버텨낼 수 있습니다.
멱등성과 사전 조건
멱등성만으로는 충분하지 않습니다. 예를 들어 "잔액이 $1,000을 넘으면 A에서 B로 $100을 이체한다"는 워크플로가 승인되었다고 가정합시다. 이 워크플로가 커밋되어 실행 중 충돌했다가 재개됩니다. 만약 멱등성 키만 확인한다면 재개된 실행에서 이체는 정확히 한 번만 일어납니다. 여기까지는 맞습니다. 그런데 충돌과 재개 사이에 다른 워크플로가 A의 잔액을 $500으로 떨어뜨려 놓았다면 어떨까요? 멱등성 검사는 여전히 통과합니다. 하지만 사전 조건은 더 이상 성립하지 않습니다. 사전 조건 검사가 없다면, 우리는 마이너스 잔액(overdraft)을 그대로 출고하게 됩니다.
따라서 결과를 만드는 모든 행동(consequential action)에는 다음 두 가지가 모두 필요합니다.
- 멱등성 키(Idempotency key): 중복 실행(double-execute)을 막아 줍니다.
- 사전 조건 검사(Precondition check): 현재 상태가 승인 당시의 조건과 여전히 일치하는지 확인합니다.
사후 검증(Post-action verification)
"도구가 200을 반환했다"는 것은 검증이 아닙니다. 진짜 검증은 대상 상태(target state)를 다시 읽어서 부수 효과(side effect)가 실제로 발생했는지 확인하는 것입니다. 흔한 방식은 다음과 같습니다.
- 데이터베이스 갱신:
UPDATE ... RETURNING *을 실행한 뒤 반환된 행(row)이 의도한 상태와 일치하는지 단정(assert)합니다.
- 이메일 발송: 전송이 끝나면 발송함(sent folder)에서 해당 메시지 ID를 다시 확인합니다.
- 파일 쓰기: 파일을 다시 읽어 해시(hash)값을 비교합니다.
- API 호출: 대상 자원(target resource)에 후속
GET을 한 번 더 보냅니다.
검증이 실패하면 워크플로는 "고장난 줄 알고 있는 상태(known-bad state)"에 빠진 셈입니다. 이때 롤백이 발동(engage)합니다.
롤백 계획(Rollback plans)
제안 후 커밋(Lesson 15)에서 결과를 만드는 모든 행동에는 롤백 계획이 함께 따라붙습니다. 롤백 유형은 다음과 같이 나뉩니다.
- 인밴드 롤백(In-band rollback): 부수 효과를 직접 되돌립니다.
INSERT 뒤에 DELETE를 호출하거나, 발송 뒤에 정정 메일(Send-correction-email)을 보내는 식입니다.
- 보상 트랜잭션(Compensating transaction): 원래 행동을 무효화(neutralize)하는 새로운 행동입니다. 표준적인 사가(SAGA) 패턴이 여기에 해당합니다.
- 아웃오브밴드 롤백(Out-of-band rollback): 사람에게 경보(alert)를 보내고 워크플로를 일시 정지시키며, 조사(investigation)를 위해 잘못된 상태를 그대로 남겨 둡니다.
되돌릴 수 없는 무동작 롤백(no-op rollback)은 제안(proposal) 단계에서 그 사실을 명시해야 합니다. 롤백이 없는 행동에는 커밋 시점에 더 강한 사람 개입(HITL, Human-In-The-Loop)이 필요합니다 (Lesson 15의 도전-응답(challenge-and-response) 방식).
EU AI 법 제14조의 운영적 해석
제14조는 고위험 시스템에 대해 "실효적인 사람 감독(effective human oversight)"을 요구합니다. 운영 관점에서 구현자(implementer)들은 이 요구를 다음과 같이 읽어 냅니다.
- 체크포인트는 감사자(auditor)가 직접 조회할 수 있어야 합니다.
- 롤백은 미리 리허설되어 있어야 합니다. 적어도 한 번은 종단 간(end-to-end)으로 시험해 본 경험이 있어야 합니다.
- 감사 추적은 배포를 견뎌야 합니다. 체크포인트 백엔드(checkpoint backend)가 일시적(ephemeral) 저장소여서는 안 됩니다.
- 검증 실패는 조용히 로그(log)만 남기는 것이 아니라 반드시 경보로 이어져야 합니다.
커밋 도중 충돌했다가 재개되어 부수 효과를 완료했지만, 검증과 롤백 경로(pathway)가 갖춰져 있지 않은 워크플로는 제14조의 기준을 통과하지 못합니다.
가장 날카로운 실패 양상: 중복 실행(double-execute)
이 분야에서 가장 흔히 보고되는 프로덕션 사고는 다음과 같은 순서를 따릅니다.
- 행동이 승인되고 멱등성 키
k가 부여됩니다.
- 커밋이 시작되고, 실행이 끝나며, 200이 반환됩니다.
- 워크플로가 "커밋됨(committed)" 상태를 지속화하기 전에 충돌합니다.
- 워크플로가 재개되어 "승인됐지만 아직 커밋 안 됨(approved but not committed)" 상태로 인식하고 행동을 다시 실행합니다.
- 부수 효과가 두 번 발생합니다.
대응책(mitigation)은 다음과 같습니다. 실행 전에 "진행 중(in-flight)"이라는 의도(intent)를 먼저 지속화하고, 멱등성 키와 함께 행동을 실행한 다음, 사후 검증이 성공한 뒤에야 "커밋됨"으로 표시합니다. 행동은 발사(fire)됐는데 상태 쓰기가 실패한 경우에는, 검증으로 확인한 뒤 필요하다면 다시 발사해야 한다는 사실을 알 수 있습니다. 반대로 상태 쓰기는 성공했는데 행동이 실패한 경우에는, 복구 경로(recovery path)에서 검증을 통해 정확히 한 번만 발사하도록 만들 수 있습니다.
사용해보기
code/main.py는 멱등성, 사전 조건, 검증, 롤백을 모두 갖춘 체크포인트 기반 워크플로를 구현합니다. 드라이버(driver) 코드는 네 가지 시나리오(scenario)를 차례로 시뮬레이션합니다. 정상 실행(clean run), 충돌 뒤 재시도(멱등성이 잡아내는 경우), 사전 조건 실패(행동을 발사하지 않고 워크플로가 중단됨), 그리고 검증 실패(롤백이 발동됨)입니다.
산출물 만들기
outputs/skill-rollback-rehearsal.md는 제안된 워크플로를 위한 롤백 리허설(rollback-rehearsal) 시험을 설계하고, 감사 추적의 지속성(audit-trail persistence) 관점에서 체크포인트 백엔드를 점검합니다.
연습문제
-
(쉬움) code/main.py를 실행하세요. 네 가지 시나리오의 결과를 확인하세요. 커밋 중 충돌(crash-during-commit) 사례에서, 행동이 재시도 전체를 통틀어 정확히 한 번만 발사되는지 확인하세요.
-
(중간) "먼저 완료 표시를 한 다음 실제로 실행한다"는 패턴을 수정해서, 상태 쓰기가 행동 뒤에 일어나도록 순서를 뒤집어 보세요. 충돌 시나리오를 다시 실행하세요. 중복으로 발사되는 행동이 몇 번 일어나는지 측정해 보세요.
-
(중간) 구체적인 프로덕션 행동(예: "Slack 채널에 글을 올린다")에 대한 롤백 계획을 설계하세요. 인밴드, 보상 트랜잭션, 아웃오브밴드 중 어느 유형으로 분류했는지 밝히고, 그 선택의 근거를 설명하세요.
-
(중간) 여러분이 잘 아는 워크플로 하나를 고르세요. 모든 상태 전이를 식별한 뒤, 각 전이에 대해 지속성 요건(persist / do not persist)을 표시하세요. 현재 지속화하고 있지 않은 전이가 몇 개인지 세어 보세요.
-
(어려움) 리허설된 롤백 시험(Rehearsed-rollback test): 실제 워크플로를 실행하고, 강제로 충돌시킨 뒤, 롤백 경로가 발동되는지를 확인하는 종단 간 시험을 설계하세요. 이 시험은 무엇을 단정해야 할까요?
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| 체크포인트(Checkpoint) | "세이브 포인트(Save point)" | 모든 그래프 상태 전이가 지속 저장소(durable store)에 기록되는 것 |
| 임대(Lease) | "워커의 권리 주장(Worker claim)" | 워커가 한 실행을 맡고 있다는 짧은 권리 주장. 충돌하면 만료됨 |
| 사전 조건(Precondition) | "상태 게이트(State gate)" | 현재 상태가 승인된 행동의 전제와 여전히 일치한다는 단정 |
| 사후 검증(Post-action verify) | "다시 읽어 보는 검사(Re-read check)" | 대상 시스템에서 부수 효과가 실제로 일어났는지 확인 |
| 인밴드 롤백(In-band rollback) | "직접 되돌리기(Direct undo)" | 역방향 연산(inverse operation)으로 부수 효과를 되돌림 |
| 보상 트랜잭션(Compensating transaction) | "SAGA 방식 되돌리기(SAGA undo)" | 원래 행동을 무효화하는 새로운 행동 |
| 선표시-후실행(Mark-as-done-first) | "상태 쓰기 순서(Status write order)" | 커밋이 반환되기 전에 "커밋됨" 상태를 먼저 지속화하는 방식 |
| 제14조(Article 14) | "EU AI 법의 사람 감독(EU AI Act human oversight)" | 운영적으로는 조회 가능한 체크포인트, 리허설된 롤백, 감사 가능한 추적을 뜻함 |
더 읽을거리