Skip to main content

Обработка rate limits

Как безопасно обрабатывать 429, throttling и лимит повторов в GonkaGate.

Сначала прочитайте error.code, а потом решайте, нужен ли retry для 429. В GonkaGate insufficient_quota означает, что для этого запроса не хватает prepaid USD balance. rate_limit_exceeded и transfer_agent_capacity_reached обычно временные. Держите эту развилку в одном общем обработчике ретраев, чтобы все вызовы вели себя одинаково.

Решите, нужен ли retry

Если пришлоЧто это обычно значитЧто делать
429 + insufficient_quotaДля этого запроса не хватает prepaid USD balanceНе ретрайте. Покажите состояние баланса или пополнения и повторяйте запрос только после появления средств.
429 + rate_limit_exceededТрафик упёрся в лимит запросовУчитывайте Retry-After, если он пришёл, и ретрайте с небольшим лимитом повторов.
429 + transfer_agent_capacity_reachedВременное давление по capacityПодождите, аккуратно повторите запрос и держите число повторов маленьким.
429 без известного кодаОбычно это всё ещё временный throttling или pressure по capacityСначала трактуйте это как временный throttling, но логируйте полный ответ, если сбой повторяется.

Используйте один общий обработчик ретраев

Используйте один общий обработчик ретраев
const sleep = (ms: number) =>
  new Promise((resolve) => setTimeout(resolve, ms));

export async function requestWithRateLimitHandling(
  makeRequest: () => Promise<Response>,
  maxRetries = 3,
): Promise<Response> {
  for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
    const response = await makeRequest();

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

    const body = await response.clone().json().catch(() => null);
    const errorCode = body?.error?.code;

    if (errorCode === "insufficient_quota") {
      throw new Error("insufficient_quota");
    }

    if (attempt === maxRetries) {
      throw new Error("retry_budget_exhausted");
    }

    const retryAfterSeconds = Number(
      response.headers.get("Retry-After") ?? "0",
    );
    const waitMs =
      retryAfterSeconds > 0
        ? retryAfterSeconds * 1000
        : Math.min(1000 * 2 ** attempt, 8000);

    await sleep(waitMs);
  }

  throw new Error("retry_budget_exhausted");
}

Эта базовая политика делает четыре вещи: ветвится по error.code, останавливается на insufficient_quota, учитывает Retry-After и ограничивает число повторов.

Сначала читайте эти поля

  • HTTP status 429
  • error.code в JSON body
  • Retry-After, если сервер точно говорит, сколько ждать
  • x-ratelimit-*, если клиент их видит, чтобы логировать текущий лимит, оставшийся запас и окно сброса
  • x-request-id для повторяющихся сбоев или эскалации в саппорт

Поле error.message используйте только как человекочитаемый контекст. Не стройте retry-логику по тексту сообщения.

Частые ошибки

  • Считать любой 429 обычным throttling. В GonkaGate insufficient_quota — это состояние биллинга, а не повод для backoff.
  • Игнорировать Retry-After, если он пришёл. Обычно это приводит к синхронным retry и новому throttling.
  • Прятать insufficient_quota за автоматическими ретраями. Остановитесь и покажите состояние биллинга или пополнения.
  • Давать воркерам, cron-job’ам или batch-трафику ретраить бесконечно. Держите лимит повторов маленьким и защищайте пользовательский трафик.

Смотрите также

Была ли эта страница полезной?