> ## Documentation Index
> Fetch the complete documentation index at: https://comfyuiwiki.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Comfy Router 요청을 대기열에 넣기

> Comfy Router 실행을 제출하고 그 상태를 폴링한 뒤, 나중에 대기열 라우트나 Python 및 TypeScript SDK로 결과를 수집하거나 취소합니다.

`POST /v2/models/{provider}/{model}`는 모델이 끝날 때까지 연결을 유지합니다. 대기 중 전달은 동일한 모델 ID와 동일한 네이티브 요청 본문을 사용하지만, Router가 실행을 수락하는 즉시 반환합니다. `request_id`를 곧바로 돌려받고, 결과가 준비되면 같은 프로세스에서든 다른 프로세스에서든 수집하면 됩니다.

**동기 경로는 10분으로 제한됩니다.** Router의 기본 데드라인은 배포별로 구성할 수 있습니다. 이에 도달한 동기 호출은 공급자가 아직 작업 중인지와 무관하게 `504` / `deadline_exceeded`와 함께 종료됩니다. 실행이 데드라인을 초과할 수 있거나 호출자가 그만큼 오래 연결을 열어 둘 수 없다면 실행 대기열을 사용하세요. 데드라인이 과금에 대해 알려주는 것과 알려주지 않는 것은 [서버 데드라인에서 호출이 종료됨](/ko/development/comfy-router/limitations#서버-데드라인에-도달하면-호출이-끊깁니다)을 참조하세요.

생성이 유지할 수 있는 연결보다 오래 걸릴 수 있을 때, 웹 요청이 지금 반환되어야 할 때, 한 프로세스에서 제출하고 다른 프로세스에서 수집할 때, 또는 여러 생성을 동시에 진행하고 싶을 때 실행 대기열을 사용하세요. 순서, 수락, 재시도, 타임아웃, 과금 및 만료는 모두 서버에서 결정됩니다. SDK는 그 위에 폴링과 편의 기능을 더할 뿐, 그 외에는 아무것도 하지 않습니다.

## 전달 모드 선택

|       | 동기                                                                                                                  | 대기 중                                              |
| ----- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| 경로    | `POST /v2/models/{provider}/{model}`                                                                                | `POST /v2/models/{provider}/{model}/requests`     |
| 응답    | 모델의 기본 출력과 함께 `200`                                                                                                 | `request_id`와 세 개의 URL과 함께 `201`                  |
| 결과    | 응답에 포함                                                                                                              | 나중에 수집되며, 바이트 단위로 동일한 출력                          |
| 시간 제한 | Router의 [10분 데드라인](/ko/development/comfy-router/limitations#서버-데드라인에-도달하면-호출이-끊깁니다), 이후 `504` / `deadline_exceeded` | 실행에는 제한이 없습니다. 완료된 결과는 [24시간 동안 보관됩니다](#멱등성-및-과금) |

SDK(`comfy-sdk` 및 `@comfyorg/sdk`, 0.3.0 이상)는 `run` 옆에 실행 대기열을 세 가지 메서드로 노출합니다:

* \*\*`submit(model, body)`\*\*는 요청을 보내고 즉시 핸들을 반환합니다. 핸들은 `status()`, `get()`, `cancel()` 및 이벤트 이터레이터(Python에서는 `iter_events()`, TypeScript에서는 `events()`)를 제공합니다.
* \*\*`subscribe(model, body, ...)`\*\*는 진행률 콜백과 함께 제출, 폴링, 수집을 한 번의 호출로 수행합니다.
* \*\*`handle(model, request_id)`\*\*는 호출 없이 두 ID만으로 다른 프로세스에서 핸들을 재구성합니다.

두 ID 모두 요청을 지정하는 데 쓰이므로 어디서나 필요합니다: 경로는 `/v2/models/{provider}/{model}/requests/{request_id}`입니다.

<Note>
  여기서 `events()`는 Comfy Cloud 클라이언트의 `job.events()`가 **아닙니다**. 이것은 상태 경로를 폴링하여 Router 요청에 대한 실행 대기열 관측값(상태와 대기열 위치)을 산출합니다. 클라우드 쪽은 진행률, 미리보기, 출력을 전달하는 ComfyUI 워크플로 작업의 실시간 SSE 스트림입니다. `subscribe()`는 또 다른 세 번째 것입니다. 이터레이터가 전혀 아니고, 제출, 폴링, 수집을 하나의 호출로 접어 놓은 것입니다. [`events()`는 `subscribe()`가 아닙니다](/ko/development/api-development/sdks#events는-subscribe가-아닙니다)를 참고하세요.
</Note>

## 실행 대기열 라우트

| 라우트                                                              | 응답                                                                                             |
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `POST /v2/models/{provider}/{model}/requests`                    | `request_id`, `status`, `queue_position`, `status_url`, `response_url`, `cancel_url`와 함께 `201` |
| `GET /v2/models/{provider}/{model}/requests/{request_id}/status` | 현재 `status`와 `queue_position`, 그리고 `Retry-After` 힌트와 함께 `200`                                  |
| `GET /v2/models/{provider}/{model}/requests/{request_id}`        | 완료되면 모델의 네이티브 출력과 함께 `200`, 아직 완료되지 않았으면 상태 본문과 함께 `202`                                       |
| `PUT /v2/models/{provider}/{model}/requests/{request_id}/cancel` | `202` `CANCELLATION_REQUESTED`, 또는 `409` `ALREADY_COMPLETED`                                   |

`status`는 `IN_QUEUE`, `IN_PROGRESS`, `COMPLETED` 중 하나입니다. 별도의 실패 또는 취소됨 상태는 없습니다. 성공하지 못한 요청은 `error_type`을 포함한 `COMPLETED`이므로, 네 번째 상태 값을 기준으로 분기하지 말고 해당 필드의 존재 여부를 기준으로 분기하세요. SDK가 이를 대신 처리해 줍니다. `get()`은 실패를 결과로 돌려주는 대신 타입이 지정된 Router 오류를 발생시키거나 reject합니다.

진행 이벤트, webhook, 우선순위 수준은 없습니다. 요청을 추적하는 방법은 상태 라우트입니다. [API 레퍼런스](/ko/development/comfy-router/reference#엔드포인트)에 각 라우트의 전체 계약이 나와 있습니다.

## 요청 제출 및 수집

[quickstart](/ko/development/comfy-router/quickstart)에서 보내는 것과 동일한 요청을 실행 대기열에 넣고 이미지를 수집합니다. 먼저 키를 `COMFY_API_KEY`로 내보내세요.

<CodeGroup>
  ```python Python theme={null}
  from comfy_sdk import Comfy

  # 환경에서 COMFY_API_KEY를 읽습니다.
  # 각 submit() 호출은 자체 Idempotency-Key를 발급하고 자동 재시도에 재사용합니다.
  with Comfy() as client:
      handle = client.models.submit(
          "bfl/flux-2-pro",
          {"prompt": "a red teapot on a windowsill, morning light"},
      )
      print("request_id:", handle.request_id)  # 모델 ID와 함께라면 다른 프로세스에 필요한 전부입니다.

      # 요청이 완료될 때까지 폴링하며, 서버가 지정한 Retry-After만큼 대기합니다.
      for update in handle.iter_events():
          print(update.status, update.queue_position)

      # 공급자의 자체 페이로드이며, models.run()이 반환하는 것과 동일한 값입니다.
      # 실패하거나 취소된 요청은 여기에서 타입이 지정된 Router 오류를 발생시킵니다.
      result = handle.get()

  print("image:", result["result"]["sample"])
  ```

  ```typescript TypeScript theme={null}
  import { comfy } from "@comfyorg/sdk";

  // 환경에서 COMFY_API_KEY를 읽습니다.
  // 각 submit() 호출은 자체 Idempotency-Key를 발급하고 자동 재시도에 재사용합니다.
  type FluxResult = { result: { sample: string } };
  const handle = await comfy.models.submit<FluxResult>("bfl/flux-2-pro", {
    prompt: "a red teapot on a windowsill, morning light",
  });
  console.log("requestId:", handle.requestId); // 모델 ID와 함께라면 다른 프로세스에 필요한 전부입니다.

  // 요청이 완료될 때까지 폴링하며, 서버가 지정한 Retry-After만큼 대기합니다.
  for await (const update of handle.events()) {
    console.log(update.status, update.queuePosition);
  }

  // models.run()이 반환하는 것과 동일한 결과입니다. 실패하거나 취소된 요청은 여기에서 거부됩니다.
  const result = await handle.get();
  if (result.kind !== "json") throw new Error("expected a JSON result");

  console.log("image:", result.data.result.sample);
  ```

  ```bash cURL theme={null}
  BASE="https://api.comfy.org/v2/models/bfl/flux-2-pro"

  # 1. 제출. Router는 request_id, status_url, response_url, cancel_url과 함께 201로 응답합니다.
  curl "$BASE/requests" \
    -H "X-API-Key: $COMFY_API_KEY" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "a red teapot on a windowsill, morning light"}'

  # 2. 상태가 COMPLETED가 될 때까지 폴링하며, 각 응답이 지정한 Retry-After 초만큼 대기합니다.
  REQUEST_ID="<request_id from the 201 body>"
  curl -i "$BASE/requests/$REQUEST_ID/status" -H "X-API-Key: $COMFY_API_KEY"

  # 3. 수집. 모델의 네이티브 출력과 함께 200, 아직 실행 중이면 상태 본문과 함께 202.
  curl "$BASE/requests/$REQUEST_ID" -H "X-API-Key: $COMFY_API_KEY"

  # 4. 아직 완료되지 않은 요청을 취소합니다. 취소 요청일 뿐, 보장은 아닙니다.
  curl -X PUT "$BASE/requests/$REQUEST_ID/cancel" -H "X-API-Key: $COMFY_API_KEY"
  ```
</CodeGroup>

모든 [모델 페이지](/ko/development/comfy-router/models)에는 동기식 스니펫 옆에, 각 모델에 맞는 이 형태가 **나중에 실행 대기열에 넣고 수집** 아래에 실려 있습니다.

### 진행 상황을 따라가며 한 번에 수집

기다리면서 동시에 진행 상황도 보여주고 싶다면, `subscribe`가 제출, 폴링, 수집을 하나의 호출로 묶어 줍니다:

<CodeGroup>
  ```python Python theme={null}
  def on_update(update):
      print(update.status, update.queue_position)

  result = client.models.subscribe(
      "bfl/flux-2-pro",
      {"prompt": "a red teapot on a windowsill, morning light"},
      on_queue_update=on_update,
      timeout=300,
  )
  ```

  ```typescript TypeScript theme={null}
  const result = await comfy.models.subscribe<FluxResult>(
    "bfl/flux-2-pro",
    { prompt: "a red teapot on a windowsill, morning light" },
    {
      onQueueUpdate: (update) => console.log(update.status, update.queuePosition),
      timeoutMs: 300_000,
    },
  );
  ```
</CodeGroup>

타임아웃은 클라이언트 측 제한이며 서버 측 의미는 없습니다. 타임아웃이 되면 `subscribe`는 예외를 발생시키기 전에 최선의 노력으로 한 번 취소를 시도합니다. 취소는 아직 실행을 시작하지 않은 요청에만 효과가 있습니다. 파트너에서 이미 진행 중인 생성은 누군가 수집하든 하지 않든 완료되고 과금됩니다. 요청이 호출자보다 오래 살아야 할 때는 `submit`을 사용하세요.

### 다른 프로세스에서 수집

`request_id`를 모델 ID 옆에 저장하세요. 핸들을 다시 만들려면 둘 다 필요하며, 사용할 때까지 아무 호출도 이루어지지 않습니다.

<CodeGroup>
  ```python Python theme={null}
  handle = client.models.handle("bfl/flux-2-pro", request_id)
  result = handle.get()
  ```

  ```typescript TypeScript theme={null}
  const handle = comfy.models.handle<FluxResult>("bfl/flux-2-pro", requestId);
  const result = await handle.get();
  ```
</CodeGroup>

### 상태 확인 또는 취소

`status()`는 한 번의 폴링이며 현재 상태를 반환합니다. `cancel()`은 아직 완료되지 않은 요청을 중지하도록 서버에 요청합니다. 이는 요청일 뿐 보장이 아닙니다. 파트너에 이미 전달된 실행은 어쨌든 완료될 수 있으며, 진실은 다음 `status()`가 알려줍니다.

<CodeGroup>
  ```python Python theme={null}
  update = handle.status()
  print(update.status, update.queue_position, update.error_type)

  handle.cancel()
  ```

  ```typescript TypeScript theme={null}
  const update = await handle.status();
  console.log(update.status, update.queuePosition, update.errorType);

  await handle.cancel();
  ```
</CodeGroup>

### 비동기 Python

`AsyncComfy`는 모든 이름, 인수, 인수 순서를 그대로 반영합니다. `run_async`가 없는 것과 같은 이유로 `submit_async`도 없습니다.

```python theme={null}
from comfy_sdk import AsyncComfy

async with AsyncComfy() as client:
    handle = await client.models.submit(
        "bfl/flux-2-pro",
        {"prompt": "a red teapot on a windowsill, morning light"},
    )
    async for update in handle.iter_events():
        print(update.status, update.queue_position)
    result = await handle.get()
```

### SDK가 발생시키는 오류

성공하지 못하고 완료된 요청은 `error_type`과 함께 `COMPLETED`로 보고됩니다. `get()`과 `subscribe()`는 이를 해당 버킷의 타입이 지정된 Router 오류로 변환합니다. Python에서는 `comfy_sdk.router_exceptions`의 클래스이고, TypeScript에서는 `routerErrors.*`입니다. 이벤트 반복자는 이 경우 예외를 발생시키지 않습니다. 이는 실행 대기열 진행 상황을 보여주는 뷰이기 때문입니다. `error_type`을 가진 완료는 마지막 관측으로 산출되고, 수집은 `get()`이 담당합니다. 제출 시 `403` `not_enabled`는 `NotEnabled`로 도착하며 터미널이므로 SDK는 이를 재시도하지 않습니다.

## 실행 대기열 응답 형태

**제출, `201`.** 이 시점에서 `status`는 항상 `IN_QUEUE`입니다. 세 개의 URL은 절대 경로이며 제출과 동일한 키로 인증됩니다.

```json theme={null}
{
  "request_id": "6f1a1a6e-6a53-4a5f-9d3a-2b3b0a1f9c21",
  "status": "IN_QUEUE",
  "queue_position": 3,
  "status_url": "https://api.comfy.org/v2/models/bfl/flux-2-pro/requests/6f1a1a6e-6a53-4a5f-9d3a-2b3b0a1f9c21/status",
  "response_url": "https://api.comfy.org/v2/models/bfl/flux-2-pro/requests/6f1a1a6e-6a53-4a5f-9d3a-2b3b0a1f9c21",
  "cancel_url": "https://api.comfy.org/v2/models/bfl/flux-2-pro/requests/6f1a1a6e-6a53-4a5f-9d3a-2b3b0a1f9c21/cancel"
}
```

`request_id`는 제출의 `X-Comfy-Request-Id` 헤더 값이기도 합니다. 옆에 모델 ID를 함께 보관하세요. 요청은 두 값 모두로 특정됩니다.

**상태, `200`.** 현재 상태와 함께 같은 형태로 돌아옵니다. `queue_position`은 내 요청보다 앞에 있는 요청 수를 세며, 실행이 맨 앞에 도달하면 `0`이 됩니다. 이 응답의 `Retry-After`는 다시 폴링할 가치가 있는 시점에 대한 Router의 추정치입니다. 이는 힌트일 뿐 제약이 아니며, 대기열 맨 뒤의 요청은 이미 실행 중인 요청보다 더 오래 기다리라는 안내를 받습니다. 더 빠르게 폴링해도 더 일찍 알 수 있는 것은 없고 자신의 rate-limit 허용량만 소모합니다.

```json theme={null}
{
  "request_id": "6f1a1a6e-6a53-4a5f-9d3a-2b3b0a1f9c21",
  "status": "IN_PROGRESS",
  "queue_position": 0,
  "status_url": "...",
  "response_url": "...",
  "cancel_url": "..."
}
```

성공하지 못하고 완료된 요청은 `error_type`과 함께 `COMPLETED`이며, 결과 조회가 `X-Comfy-Error-Type`에 담는 것과 동일한 포괄적 버킷을 전달합니다. 이 필드는 성공 시 `null`이 아니라 아예 존재하지 않습니다.

```json theme={null}
{
  "request_id": "6f1a1a6e-6a53-4a5f-9d3a-2b3b0a1f9c21",
  "status": "COMPLETED",
  "error_type": "content_policy_violation",
  "status_url": "...",
  "response_url": "...",
  "cancel_url": "..."
}
```

**결과.** `200`은 모델 자체의 네이티브 출력을 담으며, 동일한 모델과 입력에 대해 동기 경로가 반환하는 것과 바이트 단위로 동일하고, 공급자 자체의 `Content-Type`을 따릅니다. 요청이 끝나지 않은 동안에는 위의 상태 본문과 함께 `202`로 응답하므로, 결과 URL만 폴링하는 클라이언트는 한 가지 타입만 파싱하면 됩니다. 실패한 요청은 `X-Comfy-Error-Type`이 설정된 오류 응답으로 돌아오며, 동기 경로와 동일한 버킷입니다.

**취소.** `CANCELLATION_REQUESTED`와 함께 오는 `202`는 요청이 수락되었음을 의미할 뿐, 실행이 중단되었음을 의미하지 않습니다. 파트너에서 이미 진행 중인 실행은 그대로 완료될 수 있으며, 완료된 파트너 생성은 누군가 수집하든 하지 않든 과금됩니다. 이후 상태를 확인하세요. 취소가 실제로 반영된 경우 `error_type: cancelled`와 함께 `COMPLETED`로 나타납니다. 실행되기 전에 만료된 요청은 같은 방식으로 `queue_timeout`을 표시합니다. 이미 완료된 요청은 `ALREADY_COMPLETED`와 함께 `409`로 응답합니다.

## 멱등성 및 과금

* **동기 경로와 동일한 과금.** 공급자가 Comfy에 과금할 때 과금됩니다. 실행 대기열에서 대기한 시간은 과금되지 않습니다.
* **제출당 하나의 `Idempotency-Key`.** SDK는 `submit` 호출마다 새로운 키를 생성하므로, 같은 입력을 의도적으로 두 번 제출하면 두 개의 요청이 됩니다. 동일한 키로 같은 호출을 재시도해도 두 번째 실행이 실행 대기열에 들어가지 않습니다. 대신 원본 핸들을 `Idempotent-Replayed: true`와 함께 반환합니다. 응답을 잃어버려 `request_id`를 놓칠 수 있는 상황이라면 직접 키를 전달하세요. [헤더](/ko/development/comfy-router/headers)를 참고하세요.
* **결과는 만료됩니다.** 완료된 요청은 완료 후 24시간 동안 보관됩니다. 그 이후에는 상태 및 결과 조회가 `410`을 응답하고 결과는 사라집니다. 신속하게 수집하고 출력에 담긴 에셋 URL을 다운로드하세요.
* **폴링도 요청입니다.** 상태 및 결과 조회는 [호출자별 요청 비율](/ko/development/comfy-router/limitations#요청은-호출자별로-속도-제한됨)에 포함됩니다. 짧은 고정 간격으로 폴링하기보다 `Retry-After`를 따르세요.

## 실행 대기열 오류 응답

| 상태    | `X-Comfy-Error-Type`         | 의미                                                                                                                                                        |
| ----- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `402` | `insufficient_credits`       | 워크스페이스가 이 실행에 자금을 지원할 수 없습니다. 아무것도 대기열에 추가되거나 과금되지 않으며, 자금이 확보된 후에는 동일한 `Idempotency-Key`를 다시 보낼 수 있습니다.                                                  |
| `403` | `not_enabled`                | 이 호출자는 실행 대기열을 사용할 수 없습니다. 워크스페이스가 없는 키(워크스페이스 이전의 레거시 키), 자체 키 사용(bring-your-own-key) 요청, 또는 실행 대기열이 실행할 수 없는 모델이 해당합니다. 해당 요청에 대해서는 종결 상태이므로 재시도하지 마세요. |
| `404` | `model_not_found`            | `{provider}/{model}` ID가 어떤 라우터 모델과도 일치하지 않습니다.                                                                                                           |
| `404` | `request_not_found`          | 이 호출자와 모델에 대해 해당 ID를 가진 요청이 존재하지 않습니다.                                                                                                                    |
| `409` | `concurrency_limit_exceeded` | 동일한 `Idempotency-Key`가 아직 승인 처리 중입니다. `Retry-After`만큼 기다린 후 동일한 키를 다시 보내 원본 핸들을 받으세요.                                                                     |
| `409` | `invalid_input`              | 해당 `Idempotency-Key`가 다른 요청에 대해 점유되어 있습니다. 이 요청은 새 키로 보내세요.                                                                                               |
| `409` | 본문에 `ALREADY_COMPLETED`      | 취소 라우트에서만 해당합니다. 요청이 이미 완료되어 취소할 것이 없었습니다.                                                                                                                |
| `410` |                              | 요청이 존재했지만 보관 기간이 지났습니다. 완료 후 24시간이 지난 경우입니다. 해당 ID에 대해서는 영구적입니다.                                                                                          |
| `422` | `invalid_input`              | 모델이 입력을 거부했습니다. 본문에는 동기 라우트와 똑같이 필드별 상세 정보가 담겨 있습니다.                                                                                                      |

모든 오류 응답에는 `X-Comfy-Request-Id`가 포함됩니다. 고객 지원 문의 시 이 값을 함께 알려주세요.

## 다음

* [오류와 재시도](/ko/development/comfy-router/errors): 오류 응답을 확인하고 추가 청구 없이 재시도합니다.
* [API 레퍼런스](/ko/development/comfy-router/reference#엔드포인트): 각 실행 대기열 경로에 대한 전체 규격입니다.
