The Cache Was Working, But It Still Caused Duplicate API Calls

Кеш не був зламаний.

Проте три одночасні запити з одним і тим самим ім'ям користувача призвели до трьох окремих звернень до GitHub.

Це сталося в CommitPulse — API на базі Next.js, який перетворює дані GitHub на SVG-бейджи. Коли README стає вірусним, тисячі людей одночасно переглядають бейдж. Це створює величезне навантаження.

Кеш працював для послідовних запитів. Він не справлявся з одночасними.

Ось у чому проблема:

  • Запит A перевіряє кеш. Промах кешу. Запит A починає отримання даних з GitHub.
  • Запит B надходить через 5 мс. Він перевіряє кеш. Даних у кеші все ще немає, оскільки запит A ще не завершено. Запит B починає другий виклик.
  • Запит C надходить через 10 мс. Він також бачить промах кешу і починає третій виклик.

Це проблема «громового стада» (thundering herd problem). Промах кешу під високим навантаженням спричиняє шквал ідентичних викликів до вашого апстрім-провайдера. Якщо ви використовуєте API з обмеженням частоти запитів, як-от GitHub, це може миттєво вичерпати ваші ліміти.

Рішенням є об'єднання запитів (request coalescing).

Ви повинні відстежувати незавершені запити окремо від завершених записів у кеші. Я впровадив Map для керування запитами, що перебувають у процесі виконання (in-flight):

  • Коли запит починається, зберігайте його Promise у Map.
  • Якщо надходить другий запит із тим самим ключем, не починайте новий виклик.
  • Замість цього поверніть існуючий Promise із Map.
  • Після завершення запиту видаліть його з Map і збережіть результат у кеш.

Це гарантує, що скільки б людей одночасно не запитували ті самі дані, до API звернеться лише один виклик.

Виправляючи це, я також усунув три інші помилки у граничних випадках у тому ж файлі:

  • Помилки відсутності токена: система надсилала "undefined" як облікові дані. Я оновив код, щоб перевіряти токени перед виконанням запитів.
  • Витоки пам'яті: логіка повторних спроб залишала застарілі слухачі подій на AbortSignals. Я додав логіку очищення, щоб запобігти витокам.
  • URL-ін'єкції: імена користувачів зі спеціальними символами ламали шляхи API. Я додав кодування, щоб захистити структуру URL.

Кешу недостатньо. Вам також потрібно усувати дублювання запитів, які перебувають у процесі виконання.

Source: https://dev.to/eshaanagrawal/the-cache-was-working-and-still-causing-duplicate-api-calls-3n51