محدودیتها
سقف نرخ درخواست API دانا، هدرهای پاسخ و روش درست مدیریت خطای ۴۲۹
هر کلید API سقف نرخ خودش را دارد. پیشفرض ۶۰ درخواست در دقیقه است و از رد شدن یک کلید، بقیه کلیدهای شما آسیب نمیبینند.
پنجره چطور شمرده میشود
شمارش fixed window است، نه sliding window. دقیقه به بازههای سرراست تقسیم میشود و شمارنده سر هر بازه از صفر شروع میکند.
این یک نتیجه عملی دارد. فرض کنید ۶۰ درخواست را در ثانیههای پایانی یک بازه بفرستید و ۶۰ تای بعدی را در ثانیههای آغازین بازه بعد. هر دو دسته میگذرند، یعنی برای یک لحظه دو برابر سقف رد شده است. پس بار سنگین را پخش کنید و به مرز پنجره تکیه نکنید.
هدرهای پاسخ روی ۴۲۹
وقتی از سقف رد شوید، پاسخ 429 این چهار هدر را همراه دارد:
| هدر | معنا |
|---|---|
Retry-After | چند ثانیه دیگر پنجره باز میشود |
X-RateLimit-Limit | سقف همین کلید |
X-RateLimit-Remaining | باقیمانده، که اینجا همیشه صفر است |
X-RateLimit-Reset | زمان باز شدن پنجره به شکل unix timestamp |
بدنه پاسخ روی رابط OpenAI:
{
"error": {
"message": "Rate limit exceeded.",
"type": "rate_limit_error",
"param": null,
"code": null
}
}اول type را بخوانید
کد 429 چهار علت جدا دارد و دو موردشان با تلاش مجدد حل میشوند. پیش از تلاش مجدد، فیلد type را نگاه کنید:
مقدار type | معنا | تلاش مجدد؟ |
|---|---|---|
rate_limit_error | سقف نرخ همین کلید | بله، بعد از Retry-After |
capacity_busy | صف موقت سرویس | بله، بعد از eta_seconds |
insufficient_quota | اعتبار تمام شده | خیر، باید شارژ کنید |
window_cap | سقف پنجره توکن | خیر، تا زمان reset_at صبر کنید |
شرح کامل هر چهار حالت با نمونه بدنه در خطاها آمده است.
مدیریت خطا در کد
فاصلهٔ تلاش دوباره را از Retry-After بگیرید. کمی تأخیر تصادفی (jitter) هم اضافه کنید تا همهٔ workerها همزمان درخواست نفرستند.
import random
import time
import httpx
def call_with_retry(payload, api_key, max_attempts=3):
for attempt in range(max_attempts):
response = httpx.post(
"https://api.dana.expert/v1/chat/completions",
headers={"Authorization": f"Bearer {api_key}"},
json=payload,
timeout=120,
)
if response.status_code != 429:
response.raise_for_status()
return response.json()
kind = response.json().get("error", {}).get("type")
if kind not in ("rate_limit_error", "capacity_busy"):
raise RuntimeError(f"۴۲۹ غیرقابل تلاش مجدد: {kind}")
wait = float(response.headers.get("Retry-After", 2**attempt))
time.sleep(wait + random.random())
raise RuntimeError("سقف نرخ بعد از سه تلاش هنوز باز نشده بود")سقف هر کلید
سقف روی خودِ کلید مینشیند، نه روی حساب. در کنسول دانا میتوانید برای هر کلید مقدار جداگانه بگذارید.
الگویی که معمولا جواب میدهد: یک کلید پرسقف برای سرویس اصلی، یک کلید کمسقف برای اسکریپتهای تست. اسکریپتی که از کنترل خارج شود، آنوقت فقط سهم خودش را میسوزاند.
نکتهها
- درخواستهای ناموفق هم شمرده میشوند. شمارش پیش از رسیدن به مدل انجام میشود، پس یک
400هم یک درخواست است. - streaming و non-streaming فرقی ندارند؛ هر کدام یک درخواستاند، هرچند پاسخ streaming دقایقی طول بکشد.
- شمارش با شناسه کلید انجام میشود. چند سرور که یک کلید مشترک دارند، در یک پنجره سهیماند.
- برای حجم بالا با پشتیبانی دانا تماس بگیرید.
صفحههای مرتبط
- خطاها - همه کدها و فرمتهای خطا
- حساب و کلید API - ساخت و باطل کردن کلید
- قیمت و توکن - سقف اعتبار و شمارش توکن