Estoy tratando de obtener un registro de una base de datos. Debido a las condiciones de la carrera, es posible e incluso probable que el récord no esté allí cuando intento buscarlo por primera vez. ¿Cómo envuelvo esto en una lógica de reintento sin volverme loco? Parece que soy demasiado estúpido para eso.
const booking = await strapi.query("api::booking.booking").findOne({ where: { id: id, }, }); Este código debe volver a intentarlo n veces con un retraso de t milisegundos. Gracias y mucho amor.
Lo que he probado:
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);El error lanzado:
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 functionEse enfoque de promise.reject() / promise.resolve() no va a funcionar, no puede resolver una promesa desde el exterior. Y no debería necesitarlo, ¡simplemente return / throw desde su función async ! El único lugar donde necesita construir una new Promise es en una pequeña función de ayuda
function delay(t) { return new Promise(resolve => { setTimeout(resolve, t); }); }Entonces puedes escribir tu función de manera recursiva:
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; }o incluso de manera iterativa:
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"); } } }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);Simulacro utilizado:
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"); } }); };