
AI에게 맡긴 장시간 처리가 도중에 중단되어 전부 다시 시작하게 된다면 ― 체크포인트와 멱등성으로 '재개 가능한' 작업 설계하기
요약
AI 에이전트의 장시간 작업 중단 시 발생하는 비용과 시간 손실을 방지하기 위한 설계 방법을 다룹니다. 체크포인트와 멱등성 개념을 활용하여 작업 중단 시 처음부터 다시 시작하지 않고 재개할 수 있는 구조를 제안합니다.
핵심 포인트
- 체크포인트: 작업 완료 시마다 외부(파일/DB)에 상태를 기록하여 재개 가능하게 설계
- 멱등성: 동일한 작업을 여러 번 실행해도 결과가 중복되거나 망가지지 않도록 보장
- try/catch의 한계: 예외 억제는 가능하나 프로세스 중단 시 상태 인계는 불가능함
- 추가 전용(append-only) 로그 방식: 쓰기 도중 중단되어도 이전 기록을 안전하게 보존
서론 ― "3분이면 끝날 예정이었는데"가 가장 괴롭다
안녕하세요, 아키라파파(あきらパパ)입니다.
AI 에이전트나 LLM에 다음과 같은 처리를 맡겨본 적이 없으신가요?
- 500건의 문서를 일괄적으로 요약하기
- 수백 장의 이미지에 대해 한 장씩 설명문 생성하기
- 대량의 로그를 순서대로 분류 및 태그 지정하기
이런 "장시간 실행되는 처리"를 AI에게 던지면, 대개 8할 정도 진행되었을 때 중단됩니다. Rate Limit (속도 제한), 네트워크 타임아웃, 가끔 발생하는 잘못된 JSON. 그리고 많은 스크립트는 중단되는 순간 처음부터 다시 시작하게 됩니다.
이미 성공했던 400건분의 API 호출 비용도, 시간도, 모두 허공으로 날아갑니다. 이는 정신적으로 상당히 괴로운 일입니다.
이 기사의 테마는 그 "전부 다시 시작"을 없애기 위한 두 가지 설계 사상입니다.
체크포인트 (checkpoint): 어디까지 끝났는지를 외부에 기록하여, 도중에 재개할 수 있도록 한다 -
멱등성 (idempotency): 동일한 처리를 두 번 실행해도 결과가 망가지지 않도록 한다
30~40줄로 작동하는 최소한의 러너(runner)를 소개하므로, 복사해서 자신의 작업에 이식할 수 있습니다.
왜 "try/catch"만으로는 부족한가
"에러가 나면 곤란하니 try/catch를 쓰면 되지 않느냐?"라는 이야기가 나오기 쉽습니다. 하지만 try/catch가 지켜주는 것은 그 1회의 실행 중에만 국한됩니다.
장시간 작업에서 정말로 곤란한 상황은 다음과 같습니다.
- 프로세스 자체가 중단됨 (OOM, 머신 재부팅, CI 타임아웃)
- Rate Limit (속도 제한)으로 인해 "오늘은 더 이상 무리"가 되어, 내일 이어서 하고 싶음
- 중간까지 결과를 DB에 썼지만, 재시도(retry) 과정에서 동일한 행을 중복해서 써버림
try/catch는 "예외를 억제"할 수는 있어도, "어디까지 끝났는지"를 다음 실행으로 인계할 수는 없습니다. 여기서 필요해지는 것이 상태를 프로세스 외부(파일이나 DB)에 두는 발상입니다.
설계 사상 1: 체크포인트는 "건당" 작성한다
체크포인트의 기본은 "1건이 끝날 때마다, 끝났다는 사실을 기록하는 것"입니다.
흔히 하는 실수는 "전부 끝난 뒤에 한꺼번에 저장"하는 것입니다. 이렇게 하면 도중에 중단되었을 때 기록이 남지 않아 의미가 없습니다. 반대로 "건당 파일 추가(append)" 방식은 비용이 적게 들며, 중단되어도 직전까지의 기록이 남습니다.
최소한의 체크포인트는 다음과 같은 생각만으로 충분합니다.
// checkpoint.ts
import { readFileSync, appendFileSync, existsSync } from "node:fs";
const CHECKPOINT_FILE = "./.checkpoint.log";
...
포인트는, 완료 로그를 "추가 전용 (append-only)"로 만드는 것입니다. 덮어쓰기가 아니라 추가 방식으로 하면, 쓰기 도중에 프로세스가 죽더라도 그 이전의 행은 무사합니다.
설계 사상 2: 멱등성 ― "두 번 해도 동일함"을 보장한다
체크포인트로 재개가 가능해지더라도, 또 다른 문제가 남습니다.
"1건째의 결과를 DB에 쓴 직후, 체크포인트를 기록하기 전에 중단된다면?"
재개하면 그 1건은 "아직 끝나지 않음"으로 취급되어 다시 한번 실행됩니다. 여기서 처리가 멱등하지 않으면 DB에 동일한 데이터가 중복으로 들어갑니다.
멱등성이란, 대략 말하자면 "동일한 입력으로 몇 번을 실행해도 시스템의 상태가 동일하게 유지되는" 성질을 말합니다. 실무에서는 다음과 같은 형태로 담보합니다.
// idempotent-write.ts
// NG: 매번 INSERT 하면 재실행 시 중복됨
// await db.insert("summaries", { docId, text });
...
"INSERT"가 아니라 "키를 이용한 upsert"로 만드는 것만으로도 재실행 시 행이 늘어나지 않습니다. 파일 출력이라면 "out/${docId}.json에 쓰기 (매번 동일한 경로에 덮어쓰기)"로도 동일한 효과를 얻을 수 있습니다.
작동하는 것: 재개 가능한 최소 러너 (40줄)
지금까지의 두 가지를 하나로 합친, 복사해서 바로 작동하는 최소 러너입니다. LLM 호출은 더미(dummy)로 처리해 두었습니다.
// runner.ts
import { loadDone, markDone } from "./checkpoint";
// 실제로는 이 부분을 LLM 호출로 교체
...
이 스크립트는 몇 번을 실행하더라도 미완료된 ID만 처리합니다. 도중에 Ctrl+C를 누르거나, 속도 제한 (Rate Limit)으로 인해 중단되더라도, 다시 실행하면 중단된 지점부터 재개합니다.
왜 markDone은 "성공한 후"에 수행해야 하는가?
processOne을 수행하기 전에 markDone을 해버리면, 처리가 실패하더라도 "완료"로 간주되어 해당 건이 영구적으로 스킵됩니다. 순서는 반드시 "본 처리 → 성공 → 기록"이어야 합니다. 이 순서를 따르면 최악의 경우에도 "중복 실행 (멱등성 (Idempotency)으로 흡수)"으로 끝나지만, "미처리 상태로 완료 처리 (데이터 결손)"라는 복구 불가능한 사고는 피할 수 있습니다.
AI에게 설계를 맡길 때의 프롬프트 예시
이 설계 사상은 AI에게 코드를 작성하게 할 때도 사용할 수 있습니다. 단순히 맡기기만 하지 말고, "재개 가능성 (Resumability)과 멱등성 (Idempotency)을 충족하라"고 명시적으로 요구하는 것이 요령입니다.
프롬프트 예시 1 (신규 구현 요청):
500건의 문서를 하나씩 요약하는 Node.js 스크립트를 작성해줘.
필수 요구사항:
- 도중에 중단되어도 재실행 시 이어서 재개할 수 있을 것 (체크포인트 (Checkpoint)를 파일에 추가)
...
프롬프트 예시 2 (기존 코드 리뷰 요청):
이 배치 처리 (Batch Processing)를 "재실행 안전성" 관점에서 리뷰해줘.
특히 "도중에 중단되었을 때 중복 쓰기나 데이터 결손이 발생하는 부분"을 지적하고,
멱등성 (Idempotency)을 갖추도록 수정안을 차분 (Diff) 형태로 제시해줘.
프롬프트 예시 3 (설계를 언어화 요청):
이 작업 (Job)이 실패할 수 있는 포인트 (타임아웃 / 속도 제한 / 프로세스 중단)를 나열하고,
각 상황에서 "어느 단계까지 진행된 상태"가 남는지 표로 만들어줘.
그 후, 재개 가능한 설계를 위해 필요한 최소한의 변경 사항을 제안해줘.
요약 ― "중간부터"는 처음부터 설계하는 것
장시간 작업 (Long-running Job)을 안심하고 AI에게 맡기기 위한 두 가지 포인트를 되짚어 봅니다.
- 체크포인트 (Checkpoint): 매 건마다 완료 상태를 추가 전용 파일에 기록한다. 재개 시에는 이 파일만 확인하면 된다.
- 멱등성 (Idempotency): 결과에 고유 키 (Unique Key)를 연결하여, INSERT가 아닌 upsert 또는 고정 경로 덮어쓰기로 처리한다. 두 번 실행해도 데이터가 망가지지 않는다.
이 두 가지는 "중단된 후에 추가하는 것"이 아니라, 처음부터 설계에 포함시켜 두어야 하는 것입니다. 500건 중 80%에서 작업이 중단되어 허탈해하는 것보다, 처음 40줄의 코드에 미리 심어두는 것이 훨씬 경제적입니다.
관련된 과거 글도 확인해 보세요: AI 시대의 결과물은 "만들고 끝"이 아니다 ― Obsidian과 TypeScript로 배송 OS 만들기
X에서도 매일 AI 활용과 개발 설계 사상을 발신하고 있습니다 → @akirapapa_ai
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기