Job과 결과

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

Sume 생성 엔드포인트는 내구성 있는 Job을 만듭니다. 제출 응답의 job_id는 연동 복구를 위해 반드시 저장해야 합니다. 프로세스가 재시작돼도 Job을 다시 조회할 수 있습니다.

유료 생성에서 queued는 정상 접수 상태입니다. 워크스페이스 동시성 한도는 워커가 Job을 processing으로 옮길 때 적용되며, API가 유효한 Job을 받을 때는 적용되지 않습니다. 큐 용량, 티어 한도, 큐 가득 참 오류는 생성 접수에서 살펴보세요.

상태

StatusMeaningTerminal
queued요청이 접수되어 Job이 실행을 기다리는 상태입니다.No
processingJob이 실행 중이거나 마무리되는 상태입니다.No
completed결과를 사용할 수 있는 상태입니다.Yes
failed공개 오류와 함께 종료 실패에 도달한 상태입니다.Yes
canceled취소가 요청되어 종료된 상태입니다.Yes

상태 폴링

지수 백오프를 사용하고 completed, failed, canceled에서 폴링을 멈추세요. 로컬 프로세스가 타임아웃됐다는 이유만으로 원래 유료 요청을 다시 제출하지 마세요.

jobs_wait

원격 MCP jobs_wait는 다음을 받습니다.

  • job_id — 단건 대기. 응답 형태는 그대로입니다(object: "job_wait").
  • job_ids — 1–400개 id와 선택적 wait_for: "all" | "any"(기본 all). 응답은 object: "job_wait_batch"이며 요청한 모든 id의 상태 스냅샷을 담습니다.

병렬 fan-out 뒤에는 N번의 단건 wait 대신 짧은 슬라이스마다 배치 wait 한 번을 우선하세요. 타임아웃 시 같은 id로 jobs_wait를 다시 호출하고, 유료 create를 다시 제출하지 마세요. wait_for: "any"여도 모든 id를 보고하며, 남은 Job은 계속 진행되고 계속 청구됩니다. 알 수 없거나 다른 워크스페이스의 id는 호출 전체를 실패시킵니다.

슬라이스에는 상한이 있고, 서버가 이를 강제합니다

timeout_seconds의 기본값은 100이고 상한은 120입니다. 스틸 이미지만 50으로 줄일 가치가 있는데, 속도 때문이 아니라(wait는 Job이 종료 상태가 되는 즉시 반환됩니다) 50초를 넘긴 이미지는 느린 것이 아니라 대개 멈춘 것이기 때문입니다.

wait 한 번은 슬라이스 내내 아무것도 전송하지 않고 열려 있는 HTTP 요청 하나이며, 어떤 엣지든 그런 요청을 결국 끊습니다. 그러면 호출자는 도구 결과를 전혀 받지 못하지만 Job은 계속 실행되고 계속 청구됩니다. 더 큰 timeout_seconds는 거부가 아니라 클램프되며, 응답의 wait_slice_clamped가 그 사실을 알려줍니다.

10분짜리 렌더는 더 긴 슬라이스를 요청하는 대신 wait를 반복해서 기다리세요. jobs_wait에서의 524(또는 522 / 523 / 525)는 전송 실패이지 Job의 결과가 아닙니다. 같은 id로 jobs_wait를 다시 호출하거나 jobs_status를 한 번 읽으세요. 유료 create를 다시 제출하지 말고, Job이 막혔다고 보고하지 마세요.

결과 가져오기

MCP에서는 jobs_resultjob_ids도 받습니다. 상한은 jobs_wait와 같은 1–400개이므로, 한 번의 wait로 기다린 wave를 N번이 아니라 한 번의 호출로 다시 읽을 수 있습니다. 응답은 job_result_batch이며, results[]는 요청 순서대로 id당 한 항목을 담고 각 항목은 ok와 함께 value 또는 형식화된 error를 가집니다. 부분 성공은 의도된 정상 동작입니다. 아직 실행 중인 id는 job_not_completed로 돌아오지만 완료된 id는 그대로 결과를 반환하며, partial_failure.failed_job_ids가 다시 읽어야 할 id를 정확히 알려줍니다. 항목마다 ok를 확인하세요. 한 id의 실패는 다른 id에 대해 아무것도 말해주지 않습니다.

결과는 완료 후에만 사용할 수 있습니다. Job이 아직 완료되지 않았다면 API는 결과가 비어 있는 척하지 않고 conflict 응답을 돌려줍니다.

이벤트 읽기

이벤트는 디버깅과 복구를 위한 공개 타임라인을 제공합니다.

  • job.created
  • job.started
  • provider.submitted
  • job.completed
  • job.failed
  • job.canceled
  • webhook.delivery

공개 이벤트는 원본 provider task id나 원본 provider URL을 노출하지 않습니다.

취소 요청

취소는 queued 또는 processing Job에 사용할 수 있습니다. provider 실행이 이미 취소로 멈출 수 없는 지점을 지났다면 Job이 그대로 끝날 수 있습니다.

통신 모드

모든 제출 엔드포인트는 mode를 받습니다. 모드는 결과를 어떻게 전달받을지만 정합니다. Job 생성 여부, 비용, 실제 실행 시간은 모드에 따라 달라지지 않습니다.

ModeHTTP 응답첫 응답에 job id서버가 블로킹하나클라이언트가 할 일
async (기본)202와 Job envelope, 폴링 URL아니오terminal이 true가 될 때까지 status_url을 폴링하고, result_ready가 true면 GET result_url.
sync같은 envelope. 종료 상태 전환을 최대 wait_timeout_seconds(최대 30)까지 기다린 뒤 응답예, 최대 30초 — waiter 용량이 없으면 그보다 짧게종료 상태면 응답에서 바로 읽으세요. 아니면 폴링하세요. 재제출하지 마세요.
subscribesync와 동일 — 같은 제한 대기sync와 동일sync와 동일. fal 스타일의 긴 대기가 필요하면 아래 클라이언트 subscribe 레시피를 async와 함께 쓰세요.
webhook202와 Job envelope, 폴링 URL. 콜백을 저장합니다아니오종료 콜백을 기다리고 서명을 검증하세요. 폴링은 백업으로 유지하세요.

mode를 생략하면 async입니다. mode 없이 webhook_url(또는 별칭 callback_url)만 보내면 webhook입니다.

제출은 Sume가 내구성 있는 job id를 확보하는 순간 접수되므로, 모든 모드가 첫 응답에 job id를 돌려줍니다. 2xx는 Job이 존재하고 유료 작업이 진행 중이라는 뜻이지, Job이 끝났다는 뜻이 아닙니다. 둘을 구분하려면 envelope의 terminalresult_ready를 읽으세요.

두 모드는 같은 제한 waiter를 돌리고 같은 envelope를 돌려줍니다. 다른 큐 API에서 넘어온 클라이언트가 subscribe를 먼저 찾기 때문에 남겨둔 이름이며, 오래 유지되는 구독도, 이벤트 스트림도, 더 긴 대기도 아닙니다. 현재 Developer API에는 SSE나 WebSocket 전송이 없습니다. GET /v1/jobs/:id/events는 스트림이 아니라 pull 스냅샷입니다.

"Subscribe"는 세 가지 다른 것을 뜻합니다

이 단어는 서로 관계없는 세 표면에서 서로 다른 대기 시간을 가리킵니다. 어느 것도 푸시 스트림이 아닙니다. 타임아웃을 잡기 전에 아래 표를 먼저 확인하세요.

등장 위치정체대기 시간
Job mode: "subscribe" (이 페이지)sync의 별칭입니다. 제출 호출에서 한 번의 제한된 HTTP 대기를 합니다.최대 wait_timeout_seconds, 상한 30초입니다.
SDK subscribeFormatRun() (TypeScript SDK)run을 만든 뒤 클라이언트 쪽에서 종료 receipt까지 폴링합니다.분 단위입니다. HTTP를 붙잡는 것이 아니라 SDK 자체 타임아웃입니다.
Format·Action·Agent의 communication.modeJob이 아니라 run의 전달 방식 선택입니다. 값은 asyncwebhook이며 subscribe는 없습니다.아무것도 블로킹하지 않습니다.

짚어 둘 결과가 두 가지 있습니다.

  • mode: "subscribe"를 보낸다고 진행 이벤트를 받는 것이 아닙니다. sync와 똑같은 30초 대기를 받을 뿐입니다. 진행 상황이 필요하면 async로 제출하고 GET /v1/jobs/:id/events를 읽거나 웹훅을 쓰세요.
  • communication.mode에는 subscribe 값이 아예 없고, 두 값의 동작도 같습니다. 실제로 전달을 켜는 것은 webhook_url을 넣는 행위입니다.

새 연동은 async(폴링하거나 이벤트를 읽는 방식) 또는 webhook(통보받는 방식)을 쓰세요. syncsubscribe는 계속 지원되며 없어지지 않습니다. 다만 30초를 넘길 수 있는 작업 — 대부분의 영상 작업이 여기에 해당합니다 — 에는 맞지 않는 도구일 뿐입니다.

30초는 대기 예산이지 Job 실행 시간이 아닙니다

wait_timeout_seconds0..30으로 클램프됩니다. 이 값은 HTTP 요청이 블로킹되는 시간을 제한할 뿐, Job이 걸릴 수 있는 시간을 제한하지 않습니다. 이미지 Job은 대개 이 안에 끝나지만, 비디오·아바타 비디오·페이스 스왑 Job은 보통 그렇지 않습니다.

대기 예산이 소진되거나, API 프로세스에 waiter 용량이 없어 블로킹 대기를 건너뛴 경우:

  1. 응답은 여전히 2xx이고 job id를 담고 있습니다. 대기 소진은 접수 실패가 아닙니다.
  2. envelope에는 status_url, result_url, events_url, cancel_urlsync 객체가 들어 있습니다. 종료 상태 전에 대기가 끝났다면 sync.timed_out이 true이고, 프로세스별 waiter 예산이 가득 차 대기를 건너뛰었다면 sync.capacity_exhausted가 true입니다.
  3. GET status_url반드시 이어가세요. next_poll_after_seconds가 있으면 그 값을 존중하고, 없으면 백오프하세요.
  4. 같은 의도로 새 유료 Job을 만들지 마세요. 제출 자체를 재시도하는 것은 괜찮습니다. 같은 Idempotency-Key를 재사용하면 두 번 청구되는 대신 원래 Job이 돌아옵니다.

asyncwebhook 응답에서 sync는 null입니다.

클라이언트 subscribe: 종료 상태까지 Job 폴링하기

클라이언트 측 subscribe()에 해당하는 공식 방식이며, 30초를 넘길 수 있는 모든 작업의 정답입니다. async로 제출하고, 폴링하고, 결과를 읽으세요. 대기가 여러분의 클라이언트 안에 있으므로 HTTP 요청을 열어둔 채 두지 않고도 타임아웃을 몇 분으로 잡을 수 있습니다.

불리언(terminal, result_ready)이나 sume_status로 폴링을 종료하세요. status 엔드포인트는 다른 큐 API에서 넘어온 클라이언트를 위해 sume_status와 일대일로 대응하는 큐 형태의 status 필드(IN_QUEUE / IN_PROGRESS / COMPLETED / FAILED / CANCELED)도 돌려줍니다. 두 값은 서로 어긋나지 않지만 섞어 쓰지는 마세요.

GET /v1/jobs/:id/result는 완료된 Job 전용입니다. 그 외에는 409 job_not_completed를 돌려주므로, 실패 사유는 Job 레코드에서 읽으세요.

1단계 — 제출:

응답에는 request_id(job id), status_url, result_url, next_poll_after_seconds가 담깁니다.

2단계 — "terminal": true가 될 때까지 폴링:

3단계 — "result_ready": true가 되면 결과 가져오기:

어떤 HTTP 클라이언트로도 이 루프를 돌릴 수 있습니다. OkHttp나 Ktor를 쓰는 Kotlin이라면 형태는 이렇습니다.

클라이언트 타임아웃은 Job을 취소하지 않습니다. Job은 계속 실행되고 계속 청구되며, 여러분이 지켜보기를 멈춘 것뿐입니다. job id를 저장했다가 status_url에서 다시 이어가거나, 명시적으로 취소하세요.

TypeScript라면 @sume-com/sdkwaitForJob이 바로 이 루프입니다.

Job 웹훅은 종료 상태 전용입니다

mode: "webhook"은 공개 HTTPS webhook_url로 정확히 세 가지 이벤트(job.completed, job.failed, job.canceled)만 전달합니다. 진행 상황이나 부분 웹훅은 없습니다. Sume는 {timestamp}.{raw_body}에 대한 HMAC SHA-256으로 원본 본문에 서명하고 x-sume-webhook-timestampx-sume-webhook-signature: sume-v1=…를 보냅니다. payload와 검증 코드는 웹훅에서 살펴보세요.

웹훅은 전달 최적화이지 유일한 복구 경로가 아닙니다. 전달이 누락되거나 재시도될 때를 위해 status_url 폴링을 쓸 수 있게 유지하세요.

Action, Format, Agent Completion run은 자체 *.run.terminal 이벤트를 쓰는 별도 표면입니다. Run 웹훅을 참고하세요.

Idempotency

클라이언트 타임아웃이나 네트워크 실패 뒤 재시도할 때는 제출 요청에 Idempotency-Key를 보내세요.

같은 키는 같은 연산과 payload에만 재사용하세요.

결과 형태

완료된 Job은 artifact를 포함할 수 있습니다.

결과의 Sume 미디어 URL을 사용하세요. 원본 provider URL은 공개 API 출력이 아닙니다.