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
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
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"); } } }