Вопрос или проблема
Я делаю запрос с помощью eleventy-fetch следующим образом:
let response = await EleventyFetch(url, {
duration: "1h",
type: "json"
});
Однако иногда он завершается с ошибкой:
Плохой ответ для [url] (429): Слишком много запросов (через ошибку)
Я знаю, что запрашиваю слишком часто, поэтому хочу реализовать экспоненциальное ожидание. Однако моя первая попытка не сработала:
let response;
let attempts = 0;
const maxAttempts = 5;
while (attempts < maxAttempts) {
try {
response = await EleventyFetch(url, {
duration: "1h",
type: "json"
});
break; // Если запрос успешен, выход из цикла
} catch (err) {
if (err.response && err.response.status === 429) {
attempts++;
const waitTime = Math.pow(2, attempts) * 1000; // Экспоненциальное ожидание
console.warn(`Лимит частоты превышен. Повторный запрос через ${waitTime / 1000} секунд...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} else {
throw err; // Если это не ошибка 429, выбросить ошибку снова
}
}
}
Ошибка продолжает возникать, и экспоненциальное ожидание не происходит. Что я сделал не так?
Вам следует искать err.cause
, а не err.response
.
Исходный код RemoteAssetCache.js для eleventy-fetch показывает, где возникает ошибка:
if (!response.ok) {
throw new Error(
`Плохой ответ для ${this.displayUrl} (${response.status}): ${response.statusText}`,
{ cause: response },
);
}
Здесь ответ прикреплён к ошибке как свойство cause
.
Чтобы сделать ваше экспоненциальное ожидание работающим, вам просто нужно заменить err.response
на err.cause
:
let response;
let attempts = 0;
const maxAttempts = 5;
while (attempts < maxAttempts) {
try {
response = await EleventyFetch(url, {
duration: "1h",
type: "json"
});
break; // Если запрос успешен, выход из цикла
} catch (err) {
if (err.cause && err.cause.status === 429) {
attempts++;
const waitTime = Math.pow(2, attempts) * 1000; // Экспоненциальное ожидание
console.warn(`Лимит частоты превышен. Повторный запрос через ${waitTime / 1000} секунд...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} else {
throw err; // Если это не ошибка 429, выбросить ошибку снова
}
}
}
Ответ или решение
Чтобы корректно обрабатывать ошибки 429 (Too Many Requests) при использовании библиотеки eleventy-fetch
, вам необходимо внести небольшие изменения в ваш код для реализации механизма экспоненциального отката (exponential backoff). Проблема заключается в том, что вы ищете err.response
, когда на самом деле нужная информация находится в err.cause
.
Вот корректный пример кода с обработкой ошибок 429:
let response;
let attempts = 0;
const maxAttempts = 5;
while (attempts < maxAttempts) {
try {
response = await EleventyFetch(url, {
duration: "1h",
type: "json"
});
break; // Если запрос успешен, выходим из цикла
} catch (err) {
// Теперь проверяем err.cause, а не err.response
if (err.cause && err.cause.status === 429) {
attempts++;
const waitTime = Math.pow(2, attempts) * 1000; // Экспоненциальный откат
console.warn(`Лимит частоты превышен. Повторная попытка через ${waitTime / 1000} секунд...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} else {
throw err; // Если это не ошибка 429, повторно выбрасываем ошибку
}
}
}
Объяснение изменений:
-
Использование
err.cause
: Вместо проверкиerr.response
, вам нужно использоватьerr.cause
, поскольку именно туда библиотекаeleventy-fetch
помещает объект ответа, в котором содержится статус ошибки. -
Логика повторных попыток: Если возникает ошибка 429, увеличивается количество попыток, рассчитывается время ожидания с помощью экспоненциального отката, и происходит пауза перед следующей попыткой.
-
Проверка на другие ошибки: Если ошибка не является 429, она повторно выбрасывается, что позволяет обработать её в другом месте вашего приложения.
С помощью этих изменений, вы сможете эффективно обрабатывать ошибки 429 и минимизировать вероятность получения этих ошибок, что сделает ваши запросы к API более устойчивыми.