# 속도 제한 및 동시성

Tripo API는 속도 제한과 동시성 제한을 적용하여 서비스 안정성과 공정한 사용을 보장합니다.

## 비율 제한

속도 제한은 특정 기간 내에 수행할 수 있는 API 요청 수를 제한합니다.

### 제한 규칙

- 비율 제한은 **API Key** 수준에서 계산됩니다.
- 한도는 엔드포인트에 따라 다릅니다. `/v3/generation/*`와 같은 생성 엔드포인트에는 더 낮은 제한이 있고, `/v3/tasks/*`와 같은 쿼리 엔드포인트에는 더 높은 제한이 있습니다.
- 한도를 초과하면 API는 오류 코드 `1007`와 함께 HTTP `429 Too Many Requests`를 반환합니다.

### 응답 헤더

모든 API 응답에는 속도 제한 관련 응답 헤더가 포함됩니다.

| 응답 헤더 | 설명 |
| :-: | :-: |
| `X-RateLimit-Limit` | 현재 기간에 허용되는 최대 요청 수 |
| `X-RateLimit-Remaining` | 현재 기간에 사용 가능한 남은 요청 수 |
| `X-RateLimit-Reset` | 속도 제한 창이 재설정될 때의 Unix 타임스탬프(초) |

### 속도 제한 시 응답

```json
{
  "code": 1007,
  "message": "Rate limit exceeded, you've generated too many requests in a short amount of time",
  "suggestion": "Please wait for a while and try again"
}
```

---

## 동시성 제한

동시성 제한은 귀하의 계정에서 **동시에** 실행할 수 있는 작업 수를 제한합니다. 이는 속도 제한과 다릅니다. 속도 제한은 요청 빈도를 제한하는 반면 동시성 제한은 병렬 실행 작업을 제한합니다.

### 작동 방식

- 동시성은 **계정** 수준에서 계산됩니다(API Key 기준이 아님).
- **작업 카테고리별로** 제한이 적용됩니다. 각 카테고리에는 자체적인 독립적인 동시성 풀이 있습니다.
- 범주의 동시성이 가득 차면 해당 범주에 대한 새 작업 생성 시 오류 코드 `2000`와 함께 HTTP `429`가 반환됩니다.
- 다른 카테고리의 작업은 **영향을 받지 않습니다** — 사용 가능한 슬롯이 있는 카테고리에서 작업을 계속 생성할 수 있습니다

### 기본 한도

모든 사용자는 범주당 **10**의 기본 동시성으로 시작합니다. 일부 카테고리에는 한도가 다릅니다(아래 표 참조).

| 카테고리 | 포함된 작업 유형 | 기본 동시성 |
| :-: | :-: | :-: |
| 3D 생성 — H 시리즈 | 텍스트-모델(H), 이미지-모델(H), 멀티뷰-모델(H) | 10 |
| 3D 생성 — P 시리즈 | 텍스트-모델(P), 이미지-모델(P), 멀티뷰-모델(P) | 5 |
| 이미지 생성 | 텍스트를 이미지로, 이미지를 이미지로, 이미지를 멀티뷰로, 편집 멀티뷰로 | 1 |
| 애니메이션 | 자동 리그, 리그 확인, 애니메이션 대상 변경 | 10 |
| 모델 처리 | 질감, 형식 변환, 다듬기 | 5 |
| 메시 작업 | 세분화, 완성, 리토폴로지 | 10 |

> **참고:** 동일한 카테고리 내의 작업은 동시성 풀을 공유합니다. 예를 들어, 10개의 H 시리즈 텍스트-모델 작업이 실행 중인 경우 하나가 완료될 때까지 H 시리즈 이미지-모델 작업을 시작할 수 없습니다. 그러나 P 시리즈 또는 이미지 생성 작업은 계속 시작할 수 있습니다.

### 동시성 초과 시 응답

```json
{
  "code": 2000,
  "message": "You have exceeded the limit of generation",
  "suggestion": "Try again later. You can also check `Retry-After` header."
}
```

응답에는 재시도하기 전에 기다려야 하는 시간(초)을 나타내는 `Retry-After` 헤더가 포함되어 있습니다.

### 동시성 증가

더 높은 동시성 제한을 요청하려면 지원 채널을 통해 당사 팀에 문의하세요. 사용자 지정 동시성은 사용 요구 사항에 따라 범주별로 구성할 수 있습니다.

---

## 429 응답 처리

### Python

```python
import time
import requests

def request_with_backoff(method, url, headers, json=None, max_retries=5):
    for attempt in range(max_retries):
        response = requests.request(method, url, headers=headers, json=json)

        if response.status_code != 429:
            return response

        retry_after = response.headers.get("Retry-After")
        reset_at = response.headers.get("X-RateLimit-Reset")

        if retry_after:
            wait = int(retry_after)
        elif reset_at:
            wait = max(int(reset_at) - int(time.time()), 1)
        else:
            wait = 2 ** attempt

        print(f"429 triggered. Waiting {wait} seconds (attempt {attempt + 1})...")
        time.sleep(wait)

    raise Exception("Maximum retry attempts exhausted")
```

### JavaScript

```javascript
async function requestWithBackoff(url, options, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status !== 429) {
      return response;
    }

    const retryAfter = response.headers.get("Retry-After");
    const resetAt = response.headers.get("X-RateLimit-Reset");
    const wait = retryAfter
      ? Number(retryAfter)
      : resetAt
        ? Math.max(Number(resetAt) - Math.floor(Date.now() / 1000), 1)
        : 2 ** attempt;

    console.log(`429 triggered. Waiting ${wait} seconds (attempt ${attempt + 1})...`);
    await new Promise(resolve => setTimeout(resolve, wait * 1000));
  }

  throw new Error("Maximum retry attempts exhausted");
}
```

## 모범 사례

- **지수 백오프 재시도 구현**: 처음에는 1초를 대기하고 매번 대기 시간을 두 배로 늘리며 최대 대기 시간을 32초로 제한합니다.
- **`Retry-After` 및 `X-RateLimit-Reset` 헤더 선호**: 제한 창이 재설정될 때까지 정확하게 기다립니다.
- **카테고리 수준 동시성을 위한 설계**: 가능한 경우 카테고리 전체에 워크로드를 분산합니다. 이미지 생성과 3D 생성에는 별도의 풀이 있습니다.
- **일괄 API 사용**: 여러 `GET /v3/tasks/{task_id}` 요청 대신 `POST /v3/tasks/list`를 사용합니다.
- **현명하게 폴링**: 작업 완료를 기다릴 때 쿼리 엔드포인트를 초과하는 대신 합리적인 간격(1~2초마다)으로 폴링합니다.
