Workflow SDK 5 취소 지원: 긴 AI 작업에는 이제 “중단 계약”이 필요하다

테크

긴 AI 작업의 문제는 오래 걸린다는 사실보다, 멈춰야 할 때 어디까지 멈췄는지 설명하기 어렵다는 점입니다. 사용자가 취소를 눌렀는데 LLM 호출은 계속 돌고, 타임아웃이 났는데 후속 업로드는 살아 있고, 쿼터가 초과됐는데 재시도가 다시 비용을 태우는 순간부터 워크플로는 기능이 아니라 운영 리스크가 됩니다.

Vercel은 2026년 6월 16일 Workflow SDK 5 beta에서 표준 AbortController와 AbortSignal이 workflow와 step 경계를 넘어 동작한다고 발표했습니다. 같은 시기 Vercel Sandbox의 최대 실행 시간이 24시간으로 늘어난 것도 신호가 분명합니다. 에이전트와 장기 실행 백엔드는 더 오래 달릴 수 있게 되었고, 따라서 더 정교하게 멈출 수 있어야 합니다.

Workflow SDK에서 AbortController 신호가 단계로 전달되고 타임아웃, 사용자 취소, 쿼터 초과에 따라 작업이 중단되는 구조도
Workflow SDK 5의 핵심은 “취소 버튼” 자체가 아니라 어떤 단계가 어떤 신호를 받아 어떤 정리 동작을 할지 명시하는 운영 계약이다.

무엇이 바뀌었나

Workflow SDK 5 beta에서는 workflow 함수 안에서 AbortController를 만들고, 그 signal을 하나 이상의 step으로 전달한 뒤, 타임아웃·경쟁 작업·외부 훅 같은 조건에서 controller.abort()를 호출할 수 있습니다. 공식 문서는 이 신호가 workflow suspension, deterministic replay, 별도 함수 invocation을 지나도 durable하게 유지된다고 설명합니다.

중요한 단서는 “cooperative cancellation”입니다. 신호가 abort되었다고 실행 중인 모든 코드가 강제로 종료되는 것은 아닙니다. step이 fetch에 signal을 넘기거나, signal.throwIfAborted()를 호출하거나, signal.aborted를 확인해야 실제 중단 의미가 생깁니다. 따라서 이 기능은 마법의 kill switch가 아니라, 각 단계가 참여해야 하는 계약입니다.

왜 개발팀에 중요한가

최근 서버리스와 에이전트 런타임은 더 긴 실행 시간을 허용하는 방향으로 움직이고 있습니다. 장기 실행은 OCR, 리포트 생성, 브라우저 자동화, 멀티 모델 에이전트, 데이터 처리 같은 업무를 API 밖으로 밀어내지 않아도 된다는 장점이 있습니다. 반대로 취소와 정리가 약하면 불필요한 토큰, 외부 API 호출, 잠긴 리소스, 중복 웹훅, 애매한 실패 상태가 늘어납니다.

커뮤니티 신호도 이 지점에 모입니다. Vercel 관련 게시판에서는 Workflow DevKit을 프로덕션 웹훅 처리에 써도 되는지, 실행 중이거나 끝난 workflow를 어떻게 cancel/kill/cleanup할지 묻는 글이 반복됩니다. 이는 문법보다 운영 모델이 궁금하다는 뜻입니다.

운영 영향

첫째, 타임아웃 정책이 코드 가까이 내려옵니다. 단순히 플랫폼 제한 시간이 아니라 “10초 안에 응답이 없으면 이 step을 abort하고 사용자에게 어떤 상태를 반환한다”는 제품 정책으로 표현할 수 있습니다.

둘째, 병렬 작업의 비용을 줄일 수 있습니다. 여러 provider나 URL을 race할 때 첫 성공 이후 나머지 작업에 abort 신호를 보내면 늦게 도착한 응답 때문에 비용과 상태가 꼬이는 일을 줄일 수 있습니다.

셋째, 재시도 정책이 더 명확해집니다. Workflow SDK 문서는 abort로 인한 오류가 FatalError로 감싸져 retry를 건너뛴다고 설명합니다. 의도적 취소를 장애 재시도와 구분하는 것은 운영 로그를 읽는 사람에게 큰 차이를 만듭니다.

실무 체크리스트

각 workflow마다 “사용자 취소”, “타임아웃”, “관리자 강제 중단”, “쿼터 초과”, “상위 요청 종료” 중 무엇이 abort 원인인지 정의합니다.

비싼 step은 시작 직후 signal.throwIfAborted()를 호출하고, fetch·AI SDK·DB 클라이언트·스토리지 SDK처럼 signal을 받을 수 있는 API에는 반드시 전달합니다.

run.cancel()과 AbortSignal을 구분합니다. 전체 workflow를 다음 suspension point에서 멈추고 싶은지, 현재 실행 중인 특정 외부 호출을 즉시 협력적으로 멈추고 싶은지 목적이 다릅니다.

취소 결과를 성공/실패와 별도 상태로 저장합니다. 예를 들어 cancelled_by_user, timed_out, quota_exceeded처럼 로그와 UI가 같은 언어를 쓰게 해야 합니다.

취소가 “정리 완료”를 의미하지 않는다는 점을 테스트합니다. 업로드 중간 파일, 외부 job id, 결제/메일/웹훅 side effect가 남는지 별도 보상 로직을 확인해야 합니다.

반론과 리스크

아직 Workflow SDK 5는 beta/pre-release 문서 기준입니다. 핵심 결제·정산·데이터 삭제처럼 되돌리기 어려운 업무는 작은 내부 workflow에서 먼저 검증하고, 버전 고정과 롤백 경로를 준비해야 합니다.

또 하나의 리스크는 취소를 과신하는 것입니다. AbortSignal을 무시하는 라이브러리나 CPU-bound 루프는 계속 실행될 수 있습니다. 외부 API가 idempotency key를 지원하지 않는다면 abort 이후에도 원격 side effect가 완료될 수 있습니다. 따라서 취소는 “멈춤 요청”이지 “세상이 되돌아감”이 아닙니다.

지금 할 일

팀에 이미 긴 AI 요청, 리포트 생성, 파일 변환, 크롤링, 테스트 자동화, agent task가 있다면 먼저 중단 가능한 경계를 그리십시오. 어떤 step이 비용을 태우고, 어떤 step이 외부 상태를 바꾸며, 어떤 step은 재시도하면 안 되는지 표시하면 Workflow SDK 5 도입 여부와 무관하게 설계 품질이 올라갑니다.

새 기능을 바로 쓰는 팀이라면 “취소 버튼”부터 만들기보다 취소 이벤트 로그, 사용자 메시지, 비용 태그, 테스트 케이스를 먼저 만드십시오. 장기 실행 워크플로의 신뢰성은 오래 버티는 능력과 정확히 멈추는 능력의 합입니다.

도입 전 30분 점검

취소 원인을 제품 언어로 명명했는가

모든 고비용 step이 signal을 받거나 검사하는가

abort와 retry 정책이 충돌하지 않는가

외부 side effect에 idempotency key가 있는가

관측성 화면에서 cancelled와 failed가 분리되는가

const controller = new AbortController();
const result = await Promise.race([
  expensiveStep(controller.signal),
  sleep("30s").then(() => null),
]);
if (result === null) controller.abort();

출처와 참고자료