> ## Documentation Index
> Fetch the complete documentation index at: https://dripart-chore-mintlify-theme-mint.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 대기 중 전달

> Comfy Router 요청을 제출하면 즉시 요청 ID를 돌려받고, 이후 상태를 추적하며 결과를 수집하거나 취소할 수 있습니다. Python, TypeScript, cURL에서 SDK의 submit, subscribe, handle을 사용하는 방법을 다룹니다.

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

**동기 경로는 10분으로 제한됩니다.** 이 제한이 바로 이 페이지가 존재하는 이유입니다. Router의 기본 데드라인은 10분이며(배포별로 구성 가능), 이에 도달한 동기 호출은 공급자가 아직 작업 중인지와 무관하게 `504` / `deadline_exceeded`와 함께 종료됩니다. 그보다 오래 실행될 수 있는 생성이나 10분 동안 연결을 열어 둘 수 없는 호출자는 실행 대기열을 사용해야 합니다. 데드라인이 과금에 대해 알려주는 것과 알려주지 않는 것은 [서버 데드라인에서 호출이 종료됨](/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 모두 요청을 지정하기 때문에 어디서나 두 ID가 필요합니다: 경로는 `/v2/models/{provider}/{model}/requests/{request_id}`입니다.

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

## 네 가지 라우트

| 라우트                                                              | 응답                                                                                             |
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `POST /v2/models/{provider}/{model}/requests`                    | `201` 응답과 `request_id`, `status`, `queue_position`, `status_url`, `response_url`, `cancel_url` |
| `GET /v2/models/{provider}/{model}/requests/{request_id}/status` | 현재 `status`와 `queue_position`을 담은 `200`, 그리고 `Retry-After` 힌트                                  |
| `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 오류를 발생시키거나 거부합니다.

진행 이벤트, 웹훅, 우선순위 수준은 없습니다. 요청을 추적하는 방법은 status 라우트입니다. [API 참조](/ko/development/comfy-router/reference#endpoints)에 각 라우트의 전체 계약이 나와 있습니다.

## 요청을 대기열에 넣기

이 예제는 [빠른 시작](/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. status가 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)에는 동기 스니펫 옆에 **Queue and collect later**라는 제목으로 해당 모델에 맞는 이 형태가 실려 있습니다.

### 진행 상황 추적과 수집을 한 번의 호출로

기다리면서 진행 상황도 함께 표시하고 싶을 때는 `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`이 설정된 오류 응답으로 돌아오며, 동기 경로와 동일한 분류를 사용합니다.

**취소.** `202`와 `CANCELLATION_REQUESTED`는 요청이 접수되었음을 의미할 뿐, 실행이 중단되었음을 뜻하지는 않습니다. 파트너 측에서 이미 전송 중인 실행은 그대로 완료될 수 있으며, 완료된 파트너 생성은 아무도 수집하지 않더라도 과금됩니다. 이후에 상태를 읽어 보세요. 취소가 적용된 경우 `error_type: cancelled`와 함께 `COMPLETED`로 표시됩니다. 실행되기 전에 만료된 요청은 같은 방식으로 `queue_timeout`을 표시합니다. 이미 완료된 요청은 `ALREADY_COMPLETED`와 함께 `409`로 응답합니다.

## 멱등성 및 과금

* **동기 라우트와 동일한 과금.** 과금은 공급자가 Comfy에 청구할 때 발생합니다. 실행 대기열에서 대기한 시간은 과금되지 않습니다.
* **제출당 하나의 `Idempotency-Key`.** SDK는 `submit` 호출마다 새로운 키를 생성하므로, 같은 입력을 두 번 의도적으로 제출하면 두 개의 요청이 됩니다. 같은 키로 같은 호출을 재시도해도 두 번째 실행이 대기열에 추가되지 않고, 원본 핸들을 `Idempotent-Replayed: true`와 함께 반환합니다. 응답 유실로 `request_id`를 잃을 수 있는 경우에는 직접 키를 전달하세요. [Headers](/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가 어떤 Router 모델로도 확인되지 않습니다.                                                                                                          |
| `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`가 포함됩니다. 고객 지원에 문의할 때 이 값을 알려주세요.

## 다음

<CardGroup cols={2}>
  <Card title="빠른 시작" icon="rocket" href="/ko/development/comfy-router/quickstart">
    동일한 모델을 위한 동기 호출로, 아무것도 없는 상태에서 이미지 한 장까지.
  </Card>

  <Card title="모델" icon="grid" href="/ko/development/comfy-router/models">
    모든 모델 페이지에는 해당 모델과 본문에 맞는 대기 중 요청 스니펫이 있습니다.
  </Card>

  <Card title="헤더" icon="list" href="/ko/development/comfy-router/headers">
    인증, 멱등성, 요청 ID, 오류 버킷, 재시도 간격.
  </Card>

  <Card title="API 레퍼런스" icon="book" href="/ko/development/comfy-router/reference#endpoints">
    네 가지 실행 대기열 경로를 필드별로 설명합니다.
  </Card>
</CardGroup>
