Diil Docs
  1. Документація
  2. Посібники

Ліміти запитів і як їх не перевищувати

Оновлено:

Content API щедрий, але не бездонний. Кілька простих лімітів тримають його швидким для всіх — а сайт, який розумно кешує, ніколи з ними не зіткнеться. Сприймайте цю сторінку як знаки обмеження швидкості на дорозі, якою ви майже завжди їдете набагато повільніше дозволеного.

Самі ліміти

Що рахуєтьсяЛімітЩо буде понад нього
Запити з однієї IP-адреси300 / хвилинуЦя IP отримує 429 до кінця хвилини.
Запити з одним ключем сайту (з усіх IP разом)600 / хвилинуЗапити з цим ключем отримують 429 до кінця хвилини.
Запити з поганим ключем з однієї IP20 / хвилинуIP блокується до кінця хвилини — навіть запити з правильним ключем отримують 429.

Фіксовані хвилинні вікна

Лічильники працюють у фіксованих вікнах по одній хвилині, а не за ковзним середнім. Запити наповнюють лічильник, а коли хвилина минає, він починає знову з нуля. Два практичні наслідки:

  • Сплеск на самому початку хвилини — це нормально, якщо загальна кількість за цю хвилину лишається в межах ліміту.
  • Щойно ви отримали 429, ніщо в межах тієї ж хвилини не допоможе. Допоможе дочекатися наступної.

Який ліміт ви зустрінете першим

Залежить від того, звідки йдуть ваші запити:

  • Серверний рендеринг на одній машині. Усі запити йдуть з IP вашого сервера, тож стелею, якої ви досягнете першою, будуть 300 на IP. У кількох серверів по 300 у кожного, але разом вони все одно ділять 600 ключа.
  • Запити з браузера. У кожного відвідувача своя IP, тож ліміт на IP майже ніколи не має значення. Але всі відвідувачі ділять один ключ сайту, а ключ отримує 600 на хвилину на весь сайт. Кеш браузера допомагає кожному відвідувачу окремо, а не натовпу.

Як виглядає 429

429 Too Many Requestshttp
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Cache-Control: no-store

{"message":"rate_limit_exceeded"}

Ось і все. Ні заголовка Retry-After, ні заголовків RateLimit-* теж немає — тож не шукайте їх. Оскільки вікна — це фіксовані хвилини, правило просте: зачекайте приблизно хвилину (з невеликою випадковістю, див. нижче) і спробуйте знову.

Повтор із backoff і jitter

Невелика обгортка над fetch, яка робить правильну річ для кожного типу збою:

  • 429 — перечекати вікно: близько 60 секунд плюс кілька випадкових секунд.
  • 5xx і мережеві помилки — експоненційний backoff із jitter: приблизно 0,5–1 с, потім 1–2 с, потім 2–4 с.
  • Будь-який інший 4xx — жодних повторів. Очікування не виправить одруківку в маркері.
lib/fetch-with-retry.tsts
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

type RetryOptions = {
  retries?: number;   // скільки додаткових спроб
  maxWaitMs?: number; // ніколи не спати довше; натомість повернути помилку
};

export async function fetchWithRetry(
  url: string,
  init: RequestInit = {},
  { retries = 3, maxWaitMs = 70_000 }: RetryOptions = {},
): Promise<Response> {
  for (let attempt = 0; ; attempt++) {
    let res: Response | undefined;
    let error: unknown;

    try {
      res = await fetch(url, init);
      // 2xx, 304 або 4xx, який очікування не виправить (400, 401, 404…): віддаємо як є
      if (res.status !== 429 && res.status < 500) return res;
    } catch (err) {
      error = err; // проблеми з мережею: DNS, тайм-аут, скинуте з’єднання
    }

    const wait =
      res?.status === 429
        ? 60_000 + Math.random() * 5_000             // вікно — хвилина: перечекати її, плюс jitter
        : 2 ** attempt * 500 * (1 + Math.random());  // 5xx / мережа: 0,5–1 с, 1–2 с, 2–4 с…

    if (attempt >= retries || wait > maxWaitMs) {
      if (res) return res; // хай викликач побачить 429 / 5xx
      throw error;
    }
    await sleep(wait);
  }
}

Користуйтеся нею терпляче там, де ніхто не чекає, і нетерпляче — там, де чекає людина:

Два способи викликуts
const headers = { 'x-crm-key': process.env.CRM_KEY! };
const url = 'https://back.sitecog.com/content/v1/pages/home?lang=en';

// Скрипт збірки чи фонова задача: охоче перечекає 429
const res = await fetchWithRetry(url, { headers });

// Рендер сторінки для відвідувача: хвилину на сторінку ніхто не чекатиме.
// 429 повертається одразу, і ви віддаєте копію, закешовану раніше.
const quick = await fetchWithRetry(url, { headers }, { retries: 1, maxWaitMs: 2_000 });

Арифметика SSR: скільки запитів робить ваш сервер?

Порахуймо. Скажімо, типовий рендер сторінки запитує дві речі: саму сторінку (/v1/pages/about) і спільні шапку й підвал (/v1/pages/common). Це два запити на перегляд сторінки. На сайті 30 сторінок двома мовами.

ПідхідЗапитів до API за хвилинуДе ламається
Без кешу, сторінка + common на кожен перегляд2 × перегляди150 переглядів / хвилину — це 2,5 відвідувача на секунду, вистачить однієї розсилки
Без кешу, кожен блок окремим запитом (скажімо, 20 блоків)20 × перегляди15 переглядів / хвилину — жвава обідня перерва
revalidate: 60, сторінка + commonне більше 30 × 2 + 1 × 2 = 62ніколи — ті самі 62 і для 10 переглядів, і для 100 000

Останній рядок — у цьому вся суть: із серверним кешем кожен унікальний URL запитується не частіше разу на хвилину, тож використання API обмежене розміром вашого сайту, а не його популярністю. Вірусний успіх перестає бути проблемою інфраструктури.

Стежте за збірками

Статична генерація — сплеск за своєю природою: збірка, що паралельно рендерить 400 сторінок двома мовами, може випустити 800 запитів за кілька секунд з однієї машини — значно більше за 300 на хвилину. Обмежте паралельність кількома сторінками водночас і використовуйте терплячий fetchWithRetry вище, щоб 429 ставив збірку на паузу на хвилину, а не валив її.

Як триматися подалі від лімітів

  1. Кешуйте на своєму боці. revalidate у Next.js, ISR або невеликий кеш у пам’яті на будь-якому Node-сервері. Рецепти — на сторінці Кешування.
  2. Один запит сторінки замість багатьох блоків. /v1/pages/:marker повертає всі секції та блоки за раз. Замовляти піцу по шматочку весело хіба що кур’єрові.
  3. Запитуйте спільний контент один раз. Блоки шапки й підвалу на сторінці commonоднакові для всіх маршрутів — нехай їх усіх обслуговує один закешований запит.
  4. Використовуйте ETag. Він не зменшує кількість запитів, але робить кожен повторний запит майже безкоштовним за трафіком. Див. ETag і 304.
  5. Не опитуйте API постійно. Питати API щосекунди, чи щось змінилося, — це саме той трафік, заради якого існують ліміти. 60-секундний кеш дає редакторам досить швидкий зворотний зв’язок, а режим Live — миттєвий.
  6. Тримайте ключі в порядку. Старе preview-розгортання чи забута cron-задача з відкликаним ключем, що працює на тому самому сервері, що й production, може спалити 20 запитів із поганим ключем за хвилину — і тоді production на цій IP теж отримує 429. Одна паршива вівця справді псує всю отару.
Швидка перевірка ключаbash
curl -s -o /dev/null -w "%{http_code}\n" \
  "https://back.sitecog.com/content/v1/langs" -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"
# 200 — усе гаразд, 401 — виправте ключ, поки щось не почало його повторювати

Усе ж отримали 429 і хочете знати, що ще може піти не так? Усі статуси — на сторінці Помилки.