제공자가 '완료'라고 할 때 AI 비디오 작업이 끝나지 않은 이유
요약
본 글은 AI 비디오 생성 서비스 Vhoo.ai의 엔지니어링 노트로, '생성 완료'와 '사용자 접근 가능한 저장소에 미디어 영속화'를 분리하는 방법을 설명합니다. 단순히 모델 실행이 성공했다고 해서 작업이 끝난 것이 아니며, 실제 다운로드 및 스토리지 저장이 완료된 후에만 최종 상태로 업데이트해야 합니다.
핵심 포인트
- AI 비디오 생성은 '생성(Generation)'과 '저장/영속화(Persistence)' 단계를 분리해야 한다.
- 업스트림 성공만을 근거로 로컬 다운로드 및 스토리지 저장을 진행하면 실패할 수 있다.
- 미디어 영속화 시 전체 파일을 메모리에 버퍼링하지 않고 스트리밍 방식으로 처리하는 것이 효율적이다.
- 작업 기록에는 공개 URL과 내부 객체 키를 모두 저장하여 데이터 무결성을 확보해야 한다.
Vhoo.ai는 레퍼런스 기반 생성과 재사용 가능한 템플릿을 제공하는 AI 이미지 및 비디오 제작 서비스입니다. Vhoo.ai 팀의 이 엔지니어링 노트는 해당 애플리케이션이 업스트림(upstream) 생성 과정과 사용자가 검색할 수 있는 결과 저장 과정을 어떻게 분리하는지를 설명합니다. AI가 작성에 도움을 주었으며, 구현 세부 사항은 현재 프로젝트 소스 코드를 기반으로 검토되었습니다. 이 글을 위해 새로운 벤치마크나 부하 테스트는 실행되지 않았습니다.
'완료'의 두 가지 의미
Vhoo.ai에서 생성 제공자(generation provider)가 비디오를 완료했다고 보고할 수 있지만, 애플리케이션은 여전히 해당 파일을 검색하여 자체 스토리지에 복사해야 합니다. 모델 실행이 성공적이라는 것은 '제공자가 미디어를 생성했는가?'라는 질문에 답하는 것입니다. 제품은 또한 '사용자의 작업에 첨부할 저장된 결과물이 있는가?'라는 질문에도 답해야 합니다. 이 두 질문을 동일하게 취급하면, 애플리케이션의 영속성(persistence) 작업이 완료되기 전에 다운로드를 실행할 수 있습니다.
Vhoo.ai는 생성 작업을 D1에, 그리고 생성된 미디어를 R2에 저장합니다. 해당 작업에는 애플리케이션 ID와 제공자의 작업 ID가 모두 포함됩니다. 폴링을 통해 완료를 보고받을 때, 애플리케이션은 비디오 URL을 추출하고, 비디오가 없는 결과는 거부하며, 미디어를 영속화(persists)한 다음, 비로소 로컬 작업을 저장된 URL과 객체 키와 함께 '완료'로 업데이트합니다. 만약 제공자가 썸네일을 공급한다면, 현재 흐름은 작업 업데이트 전에 이 또한 영속화합니다.
순서를 명시적으로 만들기
Vhoo.ai의 비디오 완료 경로는 다음 순서를 따릅니다. 이것은 애플리케이션에 붙여넣을 완전한 구현이 아닌, 흐름에 대한 설명입니다:
query the provider recorded on the task
read the completed video's URL
require a non-empty video result
...
Vhoo.ai의 경우, 이러한 순서는 로컬에서 완료 업데이트가 이루어지기 전에 미디어 다운로드 또는 스토리지 실패가 발생함을 의미합니다. 인터페이스는 상위(upstream) 성공만을 애플리케이션에 사용 가능한 저장 파일이 있다는 증거로 해석해서는 안 됩니다. 애플리케이션의 작업을 지속적으로 활성화 상태로 유지하는 것은, 두 작업 모두 하나의 로딩 상태 아래에 표시될 때에도 생성 작업과 결과 전달 작업 간의 구분을 보존합니다.
전체 비디오를 버퍼링하는 대신 파일 스트리밍
Vhoo.ai의 미디어 영속성(media persistence) 도우미는 가져온 응답 본문(response body)을 R2 쓰기 작업에 전달합니다. 이 과정에서 완전한 비디오를 먼저 인메모리 바이트 배열로 변환하지 않습니다. 이는 스토리지 쓰기를 시작하기 전에 전체 출력을 워커(Worker) 내부에 의도적으로 버퍼링하는 것을 방지합니다. 또한, 이 도우미는 저장된 파일 확장자를 선택하기 전에 응답과 지원되는 미디어 콘텐츠 유형을 확인합니다. R2의 쓰기 메서드에 대한 지원 입력은 Cloudflare R2 Workers API 레퍼런스에 문서화되어 있습니다.
Vhoo.ai는 작업 기록에 공개 결과 URL과 함께 R2 객체 키를 보관합니다. 이 두 값은 서로 다른 목적을 수행합니다: URL은 재생 및 다운로드에 유용하며, 키는 애플리케이션 스토리지 내의 객체를 식별합니다. 둘 다 유지함으로써 나중에 공용으로 노출되는 URL로부터 객체 키를 재구성하려고 시도하지 않고도 저장 작업을 할 수 있게 합니다.
데이터베이스 전환 보호
Vhoo.ai의 완료 업데이트는 작업 ID, 소유자(owner), 그리고 보류 중(pending), 제출됨(submitted), 또는 처리 중(processing)과 같은 활성 상태에 국한됩니다. 이전에 시작된 폴링(poll)의 응답이 이미 최종 상태로 이동한 작업을 무조건 덮어쓰게 해서는 안 됩니다. 업데이트 조건은 작성자(writer)가 여전히 수행할 수 있는 전환을 알려줍니다.
Vhoo.ai의 데이터베이스 가드는 전체 제공자 다운로드-저장소-데이터베이스 시퀀스를 하나의 트랜잭션으로 만들지 않습니다. 따라서 두 개의 폴러가 작업(task)을 업데이트하기 전에 지속성 작업(persistence work)을 시작할 수 있으며, 성공적인 객체 쓰기(object write)가 실패한 데이터베이스 쓰기보다 먼저 발생할 수 있습니다. 이를 명확하게 진술하는 것이 유용합니다: 데이터베이스 전환을 보호하는 것과 모든 반복되는 외부 작업을 방지하는 것은 별개의 문제입니다.
단순히 정상 경로(happy path)가 아닌, 실패 경계(failure boundaries)를 검토해야 합니다
Vhoo.ai 스타일의 생성 서비스의 경우, 유용한 검증 사례에는 결과 URL 없이 성공을 보고하는 제공자, 다운로드 실패한 소스, 지원되지 않는 미디어 유형, R2 쓰기 실패, 그리고 중복되는 폴링 응답이 포함됩니다. 또 다른 사례는 썸네일이 제공될 때 현재 완료 경로가 둘 다를 기다리기 때문에, 성공적인 비디오 지속성(persistence) 이후에 실패하는 썸네일 지속성입니다. 이들은 본 게시물에서 수행된 테스트의 결과로 주장되는 것이 아니라, 흐름(flow)에 의해 제안되는 검토 및 테스트 시나리오입니다.
Vhoo.ai가 여기서 얻는 주요 아키텍처 교훈은 애플리케이션이 저장된 결과를 기록한 지점에서 완료를 정의하는 것입니다. 제공자의 상태는 그 결정의 입력값일 뿐입니다. 애플리케이션은 여전히 해당 상태 응답과 사용자의 히스토리에 나타나는 비디오 사이의 작업을 소유합니다.
제품 컨텍스트
Vhoo.ai는 이 비동기 생성 흐름을 이미지 및 비디오 도구에 적용합니다. 한 예로, 가상의 스턴트 비디오를 위해 인물 사진과 차량 사진을 받는 Car Jump AI Video Generator가 있습니다. 이 템플릿이 창의적인 입력(creative inputs)을 정의하며, 작업 및 저장소 계층은 생성된 결과가 사용자에게 어떻게 사용 가능하게 되는지를 처리합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기