admin管理员组文章数量:1316852
I am trying to fetch a record from a database. Due to race conditions it is possible and even likely that the record isn't there when I first try to fetch it. How do I wrap this in a retry logic without going mad? I seem to be too stupid for it
const booking = await strapi.query("api::booking.booking").findOne({
where: {
id: id,
},
});
This code should retry n
times with a delay of t
milliseconds. Thanks and much love.
What I've tried:
async function tryFetchBooking(
id,
max_retries = 3,
current_try = 0,
promise
) {
promise = promise || new Promise();
// try doing the important thing
const booking = await strapi.query("api::booking.booking").findOne({
where: {
id: id,
},
});
if (!booking) {
if (current_try < max_retries) {
console.log("No booking. Retrying");
setTimeout(function () {
tryFetchBooking(id, max_retries, current_try + 1, promise);
}, 500);
} else {
console.log("No booking. Giving up.");
promise.reject(new Error("no booking found in time"));
}
promise.catch(() => {
throw new Error(`Failed retrying 3 times`);
});
} else {
console.log("Found booking with retry");
promise.resolve(booking);
}
}
const booking = await tryFetchBooking(id);
The thrown error:
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
TypeError: Promise resolver undefined is not a function
I am trying to fetch a record from a database. Due to race conditions it is possible and even likely that the record isn't there when I first try to fetch it. How do I wrap this in a retry logic without going mad? I seem to be too stupid for it
const booking = await strapi.query("api::booking.booking").findOne({
where: {
id: id,
},
});
This code should retry n
times with a delay of t
milliseconds. Thanks and much love.
What I've tried:
async function tryFetchBooking(
id,
max_retries = 3,
current_try = 0,
promise
) {
promise = promise || new Promise();
// try doing the important thing
const booking = await strapi.query("api::booking.booking").findOne({
where: {
id: id,
},
});
if (!booking) {
if (current_try < max_retries) {
console.log("No booking. Retrying");
setTimeout(function () {
tryFetchBooking(id, max_retries, current_try + 1, promise);
}, 500);
} else {
console.log("No booking. Giving up.");
promise.reject(new Error("no booking found in time"));
}
promise.catch(() => {
throw new Error(`Failed retrying 3 times`);
});
} else {
console.log("Found booking with retry");
promise.resolve(booking);
}
}
const booking = await tryFetchBooking(id);
The thrown error:
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
TypeError: Promise resolver undefined is not a function
Share
Improve this question
asked Jul 21, 2022 at 21:54
Ole SpaarmannOle Spaarmann
16.8k28 gold badges106 silver badges167 bronze badges
3
- Something like that? stackoverflow./a/44577075/5767872 – Sergey Sosunov Commented Jul 21, 2022 at 21:58
- @SergeySosunov could you give me an example how to use it in my case? I'm struggling with the phrase "This is how you call it, assuming that func sometimes succeeds and sometimes fails, always returning a string that we can log:" So how does my function of fetching a booking would fail? It either returns a record or nothing. – Ole Spaarmann Commented Jul 21, 2022 at 22:11
- This can do it well - generic async retry function. – vitaly-t Commented Aug 11, 2024 at 17:14
3 Answers
Reset to default 6That promise.reject()
/promise.resolve()
approach is not going to work, you cannot resolve a promise from the outside. And you shouldn't need to - just return
/throw
from your async
function! The only place where you need to construct a new Promise
is in a little helper function
function delay(t) {
return new Promise(resolve => {
setTimeout(resolve, t);
});
}
Then you can write your function in a recursive manner:
async function tryFetchBooking(
id,
max_retries = 3,
current_try = 0,
) {
let booking = await strapi.query("api::booking.booking").findOne({
where: {
id: id,
},
});
if (!booking) {
if (current_try < max_retries) {
console.log("No booking. Retrying");
await delay(500);
// ^^^^^^^^^^^^^^^^
booking = await tryFetchBooking(id, max_retries, current_try + 1);
// ^^^^^^^^^^^^^^^^^^^^^
console.log("Found booking with retry");
} else {
console.log("No booking. Giving up.");
throw new Error("no booking found in time");
// or if you prefer the other error message:
throw new Error(`Failed retrying 3 times`);
}
}
return booking;
}
or even in an iterative manner:
async function tryFetchBooking(id, maxRetries = 3) {
let currentTry = 0;
while (true) {
const booking = await strapi.query("api::booking.booking").findOne({
where: {
id: id,
},
});
if (booking) {
return booking;
}
if (currentTry < maxRetries) {
await delay(500);
currentTry++;
} else {
console.log("No booking. Giving up.");
throw new Error("no booking found in time");
}
}
}
to avoid using await
inside a loop, you can use recursive function to call tryFetchBooking
async function tryFetchBooking(id, currentRetry = 0) {
const maxRetries = 3;
const booking = await strapi.query("api::booking.booking").findOne({
where: {
id: id,
},
});
if (booking) {
return booking;
}
if (currentRetry < maxRetries) {
await delay(500);
currentTry++;
return tryFetchBooking(id, currentRety);
} else {
console.log("No booking. Giving up.");
throw new Error("no booking found in time");
}
}
import { strapiMock } from "./mock";
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
// Credits to @Bergi
const retryOperation = (operation, delay, retries) =>
operation().catch((reason) =>
retries > 0
? wait(delay).then(() => retryOperation(operation, delay, retries - 1))
: Promise.reject(reason)
);
const throwIfNoResult = (result) => {
if (!result) throw new Error("No result");
return result;
};
const fetchBooking = (id) => {
/*
return strapi.query("api::booking.booking").findOne({
where: {
id: id
}
});
*/
return strapiMock(id);
};
async function tryFetchBooking(id, delay = 1000, retries = 4) {
const operation = () => fetchBooking(id).then(throwIfNoResult);
const wrapped = retryOperation(operation, delay, retries);
return await wrapped;
}
tryFetchBooking(1).then(console.log).catch(console.error);
Mock used:
let cnt = 0;
export const strapiMock = (id) => {
return new Promise((resolve, reject) => {
if (cnt++ === 3) {
cnt = 0;
// resolve(null);
resolve(id);
} else {
reject("no data");
}
});
};
本文标签: nodejsHow to retry an async function with a delay in javascriptStack Overflow
版权声明:本文标题:node.js - How to retry an async function with a delay in javascript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742011849a2413030.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论