FastAPI 오래 걸리는 작업: 202와 Job ID로 응답하기
FastAPI에서 오래 걸리는 작업은 요청을 열어 둔 채 기다리지 말고 Job ID와 함께 202로 응답하세요. AI 영상 Job이라면 작업은 Sume가 하고 결과는 웹훅으로 옵니다.

FastAPI에서 오래 걸리는 작업은 작업이 끝날 때까지 요청을 열어 두지 마세요. 요청을 받으면 Job ID와 함께 202 Accepted로 응답하고, 작업은 요청 밖에서 실행하며, 클라이언트는 상태 라우트를 확인하거나 웹훅을 받게 하세요. 그 오래 걸리는 작업이 Sume API로 만드는 AI 영상이라면 작업은 이미 Sume 쪽에서 실행됩니다. 엔드포인트는 Job을 제출하고 그 ID를 저장한 뒤 반환하면 되며, BackgroundTasks 안의 루프나 Celery 워커가 영상을 기다릴 필요가 없습니다.
FastAPI 관련 내용은 FastAPI의 백그라운드 작업, 응답 상태 코드, 동시성과 async / await 페이지에서, Sume 관련 내용은 영상 생성 (영문), Job과 결과 (영문), 웹훅 (영문)에서 가져왔습니다. 모두 2026-09-27에 확인했습니다. Sume에는 FastAPI용 패키지가 없으며, 엔드포인트는 Requests로 일반 HTTPS 호출을 보냅니다.
오래 걸리는 작업에는 BackgroundTasks와 Celery 중 무엇을 써야 하나요?
작업이 어디서 실행되느냐에 따라 다릅니다. FastAPI 문서는 BackgroundTasks를 응답을 반환한 뒤 실행되는 작업으로 설명하며, 202 Accepted로 응답하고 느린 파일은 백그라운드에서 처리하는 방법까지 제안합니다. 같은 프로세스가 필요 없는 무거운 연산에는 Celery 같은 더 큰 도구를 권합니다. 이런 도구는 대개 RabbitMQ나 Redis 같은 메시지 큐 또는 작업 큐 관리자가 필요하지만, 작업을 여러 프로세스와 여러 서버에서 실행할 수 있습니다.
Sume 영상은 어느 쪽에도 맞지 않습니다. Sume 문서에 따르면 영상 생성은 보통 30초에서 몇 분이 걸리며, 그 전부가 Sume 쪽에서 진행됩니다. BackgroundTasks 안의 폴링 루프는 그동안 내내 웹 앱 안에 머물고, Celery 워커는 기다림을 다른 곳으로 옮길 뿐입니다.
| 방법 | 작업이 실행되는 곳 | 적합한 작업 |
|---|---|---|
BackgroundTasks | FastAPI 앱 안, 응답을 보낸 뒤 | 이메일 알림 같은 작은 작업, 또는 앱 자체의 변수와 객체가 필요한 작업 |
| 큐를 쓰는 Celery | RabbitMQ나 Redis에서 작업을 받는 워커 프로세스. 다른 서버에 있을 수도 있음 | 직접 실행하는 무거운 연산 |
POST /v1/videos 같은 비동기 API | Sume 쪽. 제출하면 Job ID와 폴링 URL이 바로 돌아옴 | 시작하고 결과만 받으면 되는 작업 |
FastAPI 엔드포인트에서 영상 Job은 어떻게 시작하나요?
제출하고, 저장하고, 반환합니다. 엔드포인트는 데코레이터의 status_code 매개변수로 자체 202를 설정합니다. 함수는 일반 def입니다. API를 호출하는 라이브러리가 await를 지원하지 않을 때 FastAPI 문서가 권하는 방식이며, FastAPI는 이런 경로 작동을 서버를 막는 대신 외부 스레드풀에서 실행합니다. Sume는 제출에 202와 감싸지 않은 객체로 응답하며, 이 객체에는 id, polling_url, status: "pending", model이 담깁니다.
Idempotency-Key는 요청이 아니라 여러분의 레코드에서 만듭니다. 같은 키를 같은 본문과 함께 다시 보내면 두 번째 유료 Job 대신 원래 Job이 돌아옵니다.callback_url은 공개 HTTPS URL이어야 하며, Job이 종료 상태에 도달하면 Sume가 그 URL로 POST합니다. localhost와 사설 네트워크 URL은 거부됩니다.- Requests 문서는
application/jsonContent-Type이 필요할 때json=을 쓰라고 안내하며,timeout이 없는 호출은 무기한 멈출 수 있다고 경고합니다. SUME_API_KEY는 서버 환경에만 두고, 프런트엔드 JavaScript에는 절대 넣지 마세요.
import os, requests
from fastapi import FastAPI
app = FastAPI()
@app.post("/orders/{order_id}/video", status_code=202)
def start_video(order_id: str): # plain def: runs in FastAPI's threadpool
if job := db.find_video_job(order_id): # your table: already submitted
return job
r = requests.post(
"https://api.sume.com/v1/videos",
headers={
"Authorization": f"Bearer {os.environ['SUME_API_KEY']}",
"Idempotency-Key": f"order-{order_id}-video-v1", # from the record
},
json={
"model": "sume/auto",
"prompt": db.video_prompt(order_id), # same record, same body
"callback_url": "https://example.com/hooks/sume",
},
timeout=30,
)
r.raise_for_status()
job = r.json() # id, polling_url, status: "pending"
db.save_video_job(order_id, job["id"], job["polling_url"])
return {"job_id": job["id"], "status": job["status"]}요청이 타임아웃되거나 서버가 죽으면 어떻게 되나요?
Job ID나 키가 남아 있는 한 잃는 것은 없습니다. 제출은 Sume가 내구성 있는 Job ID를 확보한 순간 수락되며, 문서는 프로세스가 재시작된 뒤에도 연동 코드가 작업을 복구할 수 있도록 그 ID를 저장하라고 안내합니다. 2xx는 Job이 존재하고 유료 작업이 진행 중이라는 뜻이지, 작업이 끝났다는 뜻이 아닙니다.
- ID를 저장하기 전에 죽은 경우: 같은
Idempotency-Key와 같은 본문으로 다시 제출하면 재전송으로 원래 Job이 돌아옵니다. 같은 키로 다른 본문을 보내면409 idempotency_conflict이므로, 프롬프트도 레코드에서 만드세요. - 직접 보낸 호출이 타임아웃된 경우: 클라이언트 쪽 타임아웃은 Job을 취소하지 않습니다. Job은 계속 실행되고 여전히 과금되므로, 새 유료 요청을 제출하지 말고 그 Job을 다시 읽으세요.
- 워커가 재시작된 경우: 저장해 둔 Job ID가 있으면 어느 프로세스든
GET /v1/jobs/{id}/status에서 그 Job을 다시 이어받을 수 있습니다.
완성된 영상은 어떻게 내 앱으로 돌아오나요?
callback_url을 통해 돌아옵니다. Sume는 종료 Job 이벤트인 job.completed, job.failed, job.canceled만 보내며, 각 이벤트는 <timestamp>.<raw_body>에 대한 HMAC-SHA256으로 서명됩니다. job.completed 페이로드의 artifacts에는 media.sume.com URL이 나열됩니다. 원본 본문은 파싱하기 전에 검증하세요. 그 라우트는 FastAPI·Django에서 Python 웹훅 HMAC 검증하기에 있습니다.
- 이벤트를 내구성 있게 저장한 뒤
2xx로 응답하세요. 어떤2xx든 됩니다. 시도마다 10초가 주어지며, Sume는 최대 10회 시도합니다. - 여러분 쪽의 멱등성 키로는
job_id를 쓰세요. 그래야 같은 전달이 반복돼도 한 행만 갱신됩니다. - 도착하지 않는 전달에 대비해 폴링을 백업으로 유지하세요. 폴링 루프와 다운로드는 Python Text-to-Video API에서 다룹니다.
출처
관련 글
연동 카테고리의 다른 글
- Gemini CLI MCP 서버: Sume 호스팅 MCP 추가하기
httpUrl과 환경 변수에서 읽는 API 키 헤더로 Sume 호스팅 MCP 서버를 Gemini CLI에 추가하고, 도구는 허용 목록으로 추린 뒤 호출 전에 확인하세요.
- GitHub Actions: Sume Format으로 릴리스 영상 만들기
GitHub 릴리스가 게시되면 Sume Format 실행을 시작하고, 릴리스 노트를 input으로 넘기고, 영상이 준비될 때까지 폴링한 뒤 릴리스에 첨부하세요.
- GitHub Copilot 코딩 에이전트에 Sume MCP 추가하기
Copilot 코딩 에이전트는 저장소 설정에서 MCP 서버를 읽습니다. COPILOT_MCP_ 시크릿에서 읽는 API 키와 tools 허용 목록으로 Sume를 추가하세요.
- GitLab 파이프라인 스케줄: 매일 밤 AI 영상 작업 실행
GitLab 예약 파이프라인을 매일 밤 실행해 날짜 기반 Idempotency-Key로 AI 영상을 시작하고, 실행 마감보다 긴 작업 타임아웃 안에서 폴링하세요.
작성자 Sume