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
JavaScript
x
6
1
const booking = await strapi.query("api::booking.booking").findOne({
2
where: {
3
id: id,
4
},
5
});
6
This code should retry n
times with a delay of t
milliseconds. Thanks and much love.
What I’ve tried:
JavaScript
1
36
36
1
async function tryFetchBooking(
2
id,
3
max_retries = 3,
4
current_try = 0,
5
promise
6
) {
7
promise = promise || new Promise();
8
9
// try doing the important thing
10
const booking = await strapi.query("api::booking.booking").findOne({
11
where: {
12
id: id,
13
},
14
});
15
16
if (!booking) {
17
if (current_try < max_retries) {
18
console.log("No booking. Retrying");
19
setTimeout(function () {
20
tryFetchBooking(id, max_retries, current_try + 1, promise);
21
}, 500);
22
} else {
23
console.log("No booking. Giving up.");
24
promise.reject(new Error("no booking found in time"));
25
}
26
promise.catch(() => {
27
throw new Error(`Failed retrying 3 times`);
28
});
29
} else {
30
console.log("Found booking with retry");
31
promise.resolve(booking);
32
}
33
}
34
35
const booking = await tryFetchBooking(id);
36
The thrown error:
JavaScript
1
3
1
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:
2
TypeError: Promise resolver undefined is not a function
3
Advertisement
Answer
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
JavaScript
1
6
1
function delay(t) {
2
return new Promise(resolve => {
3
setTimeout(resolve, t);
4
});
5
}
6
Then you can write your function in a recursive manner:
JavaScript
1
29
29
1
async function tryFetchBooking(
2
id,
3
max_retries = 3,
4
current_try = 0,
5
) {
6
let booking = await strapi.query("api::booking.booking").findOne({
7
where: {
8
id: id,
9
},
10
});
11
12
if (!booking) {
13
if (current_try < max_retries) {
14
console.log("No booking. Retrying");
15
await delay(500);
16
// ^^^^^^^^^^^^^^^^
17
booking = await tryFetchBooking(id, max_retries, current_try + 1);
18
// ^^^^^^^^^^^^^^^^^^^^^
19
console.log("Found booking with retry");
20
} else {
21
console.log("No booking. Giving up.");
22
throw new Error("no booking found in time");
23
// or if you prefer the other error message:
24
throw new Error(`Failed retrying 3 times`);
25
}
26
}
27
return booking;
28
}
29
or even in an iterative manner:
JavaScript
1
22
22
1
async function tryFetchBooking(id, maxRetries = 3) {
2
let currentTry = 0;
3
while (true) {
4
const booking = await strapi.query("api::booking.booking").findOne({
5
where: {
6
id: id,
7
},
8
});
9
10
if (booking) {
11
return booking;
12
}
13
if (currentTry < maxRetries) {
14
await delay(500);
15
currentTry++;
16
} else {
17
console.log("No booking. Giving up.");
18
throw new Error("no booking found in time");
19
}
20
}
21
}
22