대량 실행

이 문서는 영문 원고를 AI로 번역한 내용이라 표현이 어색할 수 있습니다.

노트북에서 fan-out을 돌리지 않고 Format run 목록을 밤새 남겨 둘 수 있습니다. bulk 요청은 다른 실행 엔진이 아니라, 보통 Format run의 서버 측 큐입니다. 각 item은 POST …/runs와 같은 작업 단위입니다. 샌드박스 하나, agent 턴 하나, run receipt 하나입니다.

정확한 요청·응답 스키마는 라이브 OpenAPI (https://api.sume.com/reference/json)에서 가져옵니다. 여기 표는 읽기 쉬운 요약이며, 두 번째 스키마가 아닙니다.

엔드포인트

MethodPathScope
POST/v1/formats/{format_id}/bulk-runsformats:write
POST/v1/formats/{handle}/{slug}/bulk-runsformats: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 키 규칙입니다.

  1. Bearer API 키 (Authorization: Bearer $SUME_API_KEY).
  2. 큐를 만들려면 formats:write, 폴링하려면 formats:read가 필요합니다.
  3. 팀 워크스페이스가 소유한 Format이면, 키가 그 워크스페이스에서 발급된 것이어야 합니다.
  4. 서비스 계정 키로는 Format run이나 bulk 큐를 만들 수 없습니다. 403 insufficient_scopedetails.reasonservice_account_format_runs_unsupported인 응답으로 실패합니다.

Format API 호출 트리거가 출시되기 전에 만든 키에는 이 스코프가 없습니다. 기존 키에 스코프를 추가할 수 없으니 새 키를 만드세요. Format 호출하기팀 Format에는 팀 키가 필요합니다를 참고하세요.

ScopeNeeded for
formats:writePOST …/bulk-runs (및 단일 run 생성·취소).
formats:readGET /v1/format-run-queues/{queue_id} (및 Format·run 읽기).

큐 만들기

불투명 경로:

수락된 create는 { "data": { …queue } }와 함께 **202**를 반환합니다. 목록이 창보다 길면, 그 receipt에서 이미 처음 concurrency개가 실행 중입니다.

요청 본문

FieldNotes
concurrency필수 정수 1–16. 동시에 띄워 둘 자식 Format run 수입니다.
items필수 배열, 1–100개, 제출 순서입니다. 각 항목은 POST …/runs와 같은 본문입니다.
idempotency_keyIdempotency-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

dataformat.run_queue입니다.

FieldNotes
id큐 id (frq_…).
object항상 format.run_queue입니다.
format{ "id", "slug", "title", "version" }. id는 불투명 skl_…입니다.
concurrency보낸 창 (1–16).
statusqueued / running / completed. 아래를 보세요.
countstotal, queued, running, completed, failed, canceled. 모두 필수입니다.
items제출한 item마다 한 행이며, 같은 순서입니다.
created_at, updated_atISO-8601.
finished_at큐 status가 completed가 되면 설정되고, 그 전에는 null입니다.
status_urlGET /v1/format-run-queues/{id} — 진행은 이 URL을 폴링하세요.

큐 status

StatusMeaning
queued아직 아무것도 디스패치되지 않았습니다.
runningconcurrency 창이 목록을 비우는 중입니다.
completed모든 item이 종료 상태입니다. 실패는 counts를 보세요 — 큐 completed는 "전부 성공"이 아닙니다.

counts.totalitems.length입니다. counts.running은 API가 아직 진행 중으로 보는 item을 포함합니다 (run_id가 아직 없는 클레임된 item도 running입니다).

Items

FieldNotes
index제출한 items 배열의 0부터 시작하는 위치입니다.
statusqueued / 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 statusMeaning
queued아직 시작되지 않았습니다. run_idnull입니다.
runningconcurrency 창 안입니다.
completed자식 run이 completed입니다. 종료이며 슬롯을 비웁니다.
failed자식 run이 failed(또는 여기서 failed로 기록되는 skipped)이거나, 자식이 시작되지 못했습니다. 종료이며 슬롯을 비웁니다.
canceled자식 run이 취소되었습니다. 종료이며 슬롯을 비웁니다.

run을 시작하지 못하고 실패한 item도 그 index를 차지하며 run_idnull, error는 그 생성 실패입니다 (예: format_run_failed_to_start). 나머지 큐는 계속됩니다.

자식 run이 끝나면 error는 다음과 같습니다.

자식 runItem error
completednull
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는 종료이며 슬롯을 비웁니다. 진행 중 자식이 completedfailed(흔한 배수 경로)가 되면 다음 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)를 그대로 탑니다. 시작에 실패한 자식은 그 itemfailed가 됩니다. 큐 create는 이미 202를 반환한 뒤입니다.

큐 폴링

status_url을 따르거나, idGET /v1/format-run-queues/{queue_id}를 만드세요.

200은 create와 같은 큐 객체를 반환합니다. 대시보드에는 counts, 행별 run_id / error에는 items를 쓰세요.

모든 item이 종료이면 큐는 completed이고 finished_at이 설정됩니다. counts.failedcounts.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):

CodeStatusWhat to do
unauthorized401없거나, 형식이 틀리거나, 취소되었거나, 알 수 없는 API 키입니다.
insufficient_scope403키에 formats:write가 없거나 서비스 계정 키입니다 (details.reasonservice_account_format_runs_unsupported). next_actionauthenticate입니다. 기존 키에 스코프를 덧붙일 수는 없으니 새 키를 만드세요. 빠진 스코프는 format_not_found가 아닙니다.
workspace_key_required403팀 Format인데 개인 키입니다. details.workspace_id에서 만든 키를 쓰세요.
invalid_request400concurrency가 1–16 정수가 아니거나, items가 없거나 비었거나 100개를 넘거나, item이 객체가 아니거나, items[i]instruction / input / previous_run_id / attachments 중 아무것도 없는 경우입니다. 잘못된 item은 details.index가 가리킵니다.
format_not_found404알 수 없거나, 보관되었거나, 이 키의 워크스페이스 밖이거나, 멤버가 아닌 팀 handle입니다.
format_api_trigger_disabled409이 Format의 API 호출 트리거가 꺼져 있습니다.
format_inactive409Format이 비활성입니다.
idempotency_conflict409Idempotency-Key가 다른 bulk 페이로드로 이미 사용되었습니다.
invalid_attachment / attachment_not_found / attachment_too_large / attachment_fetch_failed400 / 413 / 502큐가 생기기 전에 item의 attachments를 해석하다 발생합니다 — Format 호출하기와 같은 코드입니다.
rate_limited429retry-after초를 기다리세요. create는 write 예산을 씁니다.
studio_agent_upstream_unavailable503Sume 쪽 장애입니다. 나중에 재시도하세요.

폴링 (GET /v1/format-run-queues/{queue_id}):

CodeStatusWhat to do
unauthorized401없거나 잘못된 API 키입니다.
insufficient_scope403키에 formats:read가 없습니다. details.required_scope가 가리킵니다.
format_run_queue_not_found404알 수 없는 큐 id이거나, 다른 소유자의 큐입니다.
rate_limited429retry-after를 기다리세요. 폴링은 create와 별개인 read 예산을 씁니다.
studio_agent_upstream_unavailable503나중에 재시도하세요. 큐는 계속 비워집니다.

폴링 루프의 429503은 일시적입니다. 큐는 계속 동작합니다. 실패한 큐로 보지 말고 backoff하세요.

202 이후 자식의 지갑·접수 실패는 create를 실패시키지 않습니다. 그 item이 해당 create-run 오류와 함께 failed가 되고, 창은 남은 queued item으로 채워집니다.

처음부터 끝까지

프로덕션에서는 고정 5초 sleep 대신 exponential backoff를 쓰세요. Format이 비디오를 만들면 자식 하나도 분 단위입니다. 큐를 매초 폴링해도 이득이 없고 rate limit만 소모합니다.

끝난 자식의 미디어는 items[]run_id를 집어 실행과 결과를 따르세요.

다음