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
That 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");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With