대량 실행
이 문서는 영문 원고를 AI로 번역한 내용이라 표현이 어색할 수 있습니다.
노트북에서 fan-out을 돌리지 않고 Format run 목록을 밤새 남겨 둘 수 있습니다. bulk 요청은
다른 실행 엔진이 아니라, 보통 Format run의 서버 측 큐입니다. 각 item은
POST …/runs와 같은 작업 단위입니다. 샌드박스 하나, agent 턴 하나,
run receipt 하나입니다.
정확한 요청·응답 스키마는 라이브 OpenAPI
(https://api.sume.com/reference/json)에서 가져옵니다. 여기 표는 읽기 쉬운 요약이며,
두 번째 스키마가 아닙니다.
엔드포인트
| Method | Path | Scope |
|---|---|---|
POST | /v1/formats/{format_id}/bulk-runs | formats:write |
POST | /v1/formats/{handle}/{slug}/bulk-runs | formats:write |
GET | /v1/format-run-queues/{queue_id} | formats:read |
두 POST 경로는 쌍입니다. 새 연동에서는 {handle}/{slug}를 선호하세요. 불투명 skl_…
경로는 계속 유효합니다. 요청 본문, 헤더, 스코프, 큐 receipt는 동일합니다.
큐 목록이나 큐 전체 취소 공개 엔드포인트는 없습니다. 자식 run은
POST /v1/format-runs/{run_id}/cancel로 취소합니다 — 취소를
참고하세요.
인증
단일 Format run과 같은 API 키 규칙입니다.
- Bearer API 키 (
Authorization: Bearer $SUME_API_KEY). - 큐를 만들려면
formats:write, 폴링하려면formats:read가 필요합니다. - 팀 워크스페이스가 소유한 Format이면, 키가 그 워크스페이스에서 발급된 것이어야 합니다.
- 서비스 계정 키로는 Format run이나 bulk 큐를 만들 수 없습니다.
403 insufficient_scope와details.reason이service_account_format_runs_unsupported인 응답으로 실패합니다.
Format API 호출 트리거가 출시되기 전에 만든 키에는 이 스코프가 없습니다. 기존 키에 스코프를 추가할 수 없으니 새 키를 만드세요. Format 호출하기와 팀 Format에는 팀 키가 필요합니다를 참고하세요.
| Scope | Needed for |
|---|---|
formats:write | POST …/bulk-runs (및 단일 run 생성·취소). |
formats:read | GET /v1/format-run-queues/{queue_id} (및 Format·run 읽기). |
큐 만들기
불투명 경로:
수락된 create는 { "data": { …queue } }와 함께 **202**를 반환합니다. 목록이 창보다
길면, 그 receipt에서 이미 처음 concurrency개가 실행 중입니다.
요청 본문
| Field | Notes |
|---|---|
concurrency | 필수 정수 1–16. 동시에 띄워 둘 자식 Format run 수입니다. |
items | 필수 배열, 1–100개, 제출 순서입니다. 각 항목은 POST …/runs와 같은 본문입니다. |
idempotency_key | Idempotency-Key 헤더의 본문 표기입니다. 둘 다 보내면 헤더가 이깁니다. |
알 수 없는 최상위 필드는 거절됩니다. items는 필수입니다 — { "concurrency": 3 }은
빈 큐가 아니라 400입니다.
각 item은 instruction, input, previous_run_id, attachments 중 하나 이상을
이름 붙여야 합니다. 잘못된 item은 큐가 생기기 전에 create를 실패시킵니다 (400 invalid_request, details.index). 아무것도 디스패치되지 않습니다.
bulk 컨트롤러가 single-flight를 소유합니다. 모든 item은 on_active_run: "allow"로
실행됩니다. item에 skip이나 reject를 넣어도 이 Format의 첫 진행 중 run에서 창이
멈추지 않습니다. 자식 run에는 워크스페이스 generation concurrency가 그대로 적용됩니다.
item의 communication.webhook_url은 단일 run과 같습니다. 자식마다 종료 웹훅을 등록할
수 있습니다. 큐 객체에는 웹훅이 없습니다. 큐 단위 콜백을 기대하지 마세요.
큐 receipt
data는 format.run_queue입니다.
| Field | Notes |
|---|---|
id | 큐 id (frq_…). |
object | 항상 format.run_queue입니다. |
format | { "id", "slug", "title", "version" }. id는 불투명 skl_…입니다. |
concurrency | 보낸 창 (1–16). |
status | queued / running / completed. 아래를 보세요. |
counts | total, queued, running, completed, failed, canceled. 모두 필수입니다. |
items | 제출한 item마다 한 행이며, 같은 순서입니다. |
created_at, updated_at | ISO-8601. |
finished_at | 큐 status가 completed가 되면 설정되고, 그 전에는 null입니다. |
status_url | GET /v1/format-run-queues/{id} — 진행은 이 URL을 폴링하세요. |
큐 status
| Status | Meaning |
|---|---|
queued | 아직 아무것도 디스패치되지 않았습니다. |
running | concurrency 창이 목록을 비우는 중입니다. |
completed | 모든 item이 종료 상태입니다. 실패는 counts를 보세요 — 큐 completed는 "전부 성공"이 아닙니다. |
counts.total은 items.length입니다. counts.running은 API가 아직 진행 중으로 보는
item을 포함합니다 (run_id가 아직 없는 클레임된 item도 running입니다).
Items
| Field | Notes |
|---|---|
index | 제출한 items 배열의 0부터 시작하는 위치입니다. |
status | queued / running / completed / failed / canceled. |
run_id | 디스패치된 뒤의 자식 Format run id입니다. queued이면 null이고, 자식 run이 시작되기 전에 실패한 item도 null입니다. 전체 receipt는 GET /v1/format-runs/{run_id}입니다. |
error | { "code", "message" }이거나 null입니다. |
| Item status | Meaning |
|---|---|
queued | 아직 시작되지 않았습니다. run_id는 null입니다. |
running | concurrency 창 안입니다. |
completed | 자식 run이 completed입니다. 종료이며 슬롯을 비웁니다. |
failed | 자식 run이 failed(또는 여기서 failed로 기록되는 skipped)이거나, 자식이 시작되지 못했습니다. 종료이며 슬롯을 비웁니다. |
canceled | 자식 run이 취소되었습니다. 종료이며 슬롯을 비웁니다. |
run을 시작하지 못하고 실패한 item도 그 index를 차지하며 run_id는 null, error는
그 생성 실패입니다 (예: format_run_failed_to_start). 나머지 큐는 계속됩니다.
자식 run이 끝나면 error는 다음과 같습니다.
| 자식 run | Item error |
|---|---|
completed | null |
failed | { "code": "format_run_failed", "message": "The Format run failed." } |
canceled | { "code": "format_run_canceled", "message": "The Format run was canceled." } |
자식이 왜 실패했는지는 큐 item만이 아니라 run receipt
(GET /v1/format-runs/{run_id})에서 읽으세요.
concurrency 창
서버는 concurrency개의 자식 run을 동시에 띄운 채, 슬롯이 열리는 즉시 다음 queued
item을 시작해 목록을 비웁니다. 클라이언트가 돌리는 fan-out이 아닙니다.
진행 중 슬롯은 공개 status가 running인 item입니다. completed, failed,
canceled는 종료이며 슬롯을 비웁니다. 진행 중 자식이 completed나 failed(흔한
배수 경로)가 되면 다음 queued item이 바로 시작해 창을 가득 유지합니다. canceled
자식도 같습니다.
create가 이미 창을 채웁니다. concurrency: 3에 item 8개면 202 receipt는
running 3개와 queued 5개입니다. item 0이 끝나면 item 3이 시작되고, 남은 item이
3개 미만이 될 때까지 창은 3으로 유지됩니다.
진행을 여러 번 폴링하거나 advance해도 창은 concurrency를 넘지 않습니다.
자식 run은 보통 Format-run 접수(지갑, 워크스페이스 generation concurrency, spend cap)를
그대로 탑니다. 시작에 실패한 자식은 그 item이 failed가 됩니다. 큐 create는 이미
202를 반환한 뒤입니다.
큐 폴링
status_url을 따르거나, id로 GET /v1/format-run-queues/{queue_id}를 만드세요.
200은 create와 같은 큐 객체를 반환합니다. 대시보드에는 counts, 행별 run_id /
error에는 items를 쓰세요.
모든 item이 종료이면 큐는 completed이고 finished_at이 설정됩니다.
counts.failed와 counts.canceled로 분기하세요. 큐 completed를 성공으로 취급하지
마세요.
볼 수 없는 큐는 없는 큐와 같습니다. 404 format_run_queue_not_found (알 수 없는 id,
또는 다른 소유자의 큐).
자식 run
디스패치된 각 item은 보통 Format run입니다.
그 receipt의 status_url / result_url / events_url / cancel_url은
실행과 결과와 같습니다. 큐는 그 엔드포인트를 대체하지 않고, 위에
counts와 item 상태를 더합니다.
자식 취소(POST /v1/format-runs/{run_id}/cancel)는 그 큐 item을 canceled로 표시하고
슬롯을 다음 queued item에 넘깁니다.
멱등성
create에 Idempotency-Key를 보내세요 (헤더. 본문 idempotency_key도 받으며, 헤더가
이깁니다). 키는 Format 하나에 범위가 묶입니다.
| 재시도 | 결과 |
|---|---|
같은 키, 같은 { concurrency, items } | 202와 기존 큐. |
| 같은 키, 다른 페이로드 | 409 idempotency_conflict (details.queue_id가 원본을 가리킵니다). |
단일 run과 달리 bulk 재시도는 202로 남습니다. 큐 객체에는 idempotency_hit
필드가 없습니다.
큐 단위 웹훅은 없고, 위의 헤더/본문 키 외에 큐 전용 멱등성 동작도 없습니다.
오류
Create (POST …/bulk-runs):
| Code | Status | What to do |
|---|---|---|
unauthorized | 401 | 없거나, 형식이 틀리거나, 취소되었거나, 알 수 없는 API 키입니다. |
insufficient_scope | 403 | 키에 formats:write가 없거나 서비스 계정 키입니다 (details.reason은 service_account_format_runs_unsupported). next_action은 authenticate입니다. 기존 키에 스코프를 덧붙일 수는 없으니 새 키를 만드세요. 빠진 스코프는 format_not_found가 아닙니다. |
workspace_key_required | 403 | 팀 Format인데 개인 키입니다. details.workspace_id에서 만든 키를 쓰세요. |
invalid_request | 400 | concurrency가 1–16 정수가 아니거나, items가 없거나 비었거나 100개를 넘거나, item이 객체가 아니거나, items[i]가 instruction / input / previous_run_id / attachments 중 아무것도 없는 경우입니다. 잘못된 item은 details.index가 가리킵니다. |
format_not_found | 404 | 알 수 없거나, 보관되었거나, 이 키의 워크스페이스 밖이거나, 멤버가 아닌 팀 handle입니다. |
format_api_trigger_disabled | 409 | 이 Format의 API 호출 트리거가 꺼져 있습니다. |
format_inactive | 409 | Format이 비활성입니다. |
idempotency_conflict | 409 | 그 Idempotency-Key가 다른 bulk 페이로드로 이미 사용되었습니다. |
invalid_attachment / attachment_not_found / attachment_too_large / attachment_fetch_failed | 400 / 413 / 502 | 큐가 생기기 전에 item의 attachments를 해석하다 발생합니다 — Format 호출하기와 같은 코드입니다. |
rate_limited | 429 | retry-after초를 기다리세요. create는 write 예산을 씁니다. |
studio_agent_upstream_unavailable | 503 | Sume 쪽 장애입니다. 나중에 재시도하세요. |
폴링 (GET /v1/format-run-queues/{queue_id}):
| Code | Status | What to do |
|---|---|---|
unauthorized | 401 | 없거나 잘못된 API 키입니다. |
insufficient_scope | 403 | 키에 formats:read가 없습니다. details.required_scope가 가리킵니다. |
format_run_queue_not_found | 404 | 알 수 없는 큐 id이거나, 다른 소유자의 큐입니다. |
rate_limited | 429 | retry-after를 기다리세요. 폴링은 create와 별개인 read 예산을 씁니다. |
studio_agent_upstream_unavailable | 503 | 나중에 재시도하세요. 큐는 계속 비워집니다. |
폴링 루프의 429나 503은 일시적입니다. 큐는 계속 동작합니다. 실패한 큐로 보지 말고
backoff하세요.
202 이후 자식의 지갑·접수 실패는 create를 실패시키지 않습니다. 그 item이 해당
create-run 오류와 함께 failed가 되고, 창은 남은 queued item으로 채워집니다.
처음부터 끝까지
프로덕션에서는 고정 5초 sleep 대신 exponential backoff를 쓰세요. Format이 비디오를 만들면 자식 하나도 분 단위입니다. 큐를 매초 폴링해도 이득이 없고 rate limit만 소모합니다.
끝난 자식의 미디어는 items[]의 run_id를 집어 실행과 결과를
따르세요.
다음
- Format 호출하기 — item별 invoke 계약과 모든 제출 오류
- 실행과 결과 — 자식 receipt, 폴링, 취소
- 구조화 출력 — item마다 스키마 바인딩
- Run 웹훅 — 자식별
communication.webhook_url, 큐 콜백 아님 - 제품에 Format 임베드하기 — 단일 run 주변의 파트너 연동