Tengo una aplicación NextJS que ejecuta un setTimeout recursivo cuando se inicia el servidor. Necesito crear un punto final de API que pueda iniciar y detener este ciclo (para tener más control sobre él en producción). Este bucle se usa para procesar elementos en una base de datos que se agregan desde otro extremo de la API.
import { clearTimeout } from "timers";
var loopFlag = true;
export function loopFlagSwitch(flag: boolean) {
loopFlag = flag;
}
export async function loop() {
try {
// Retrieve all unprocessed transactions
const unprocessedTransactions = await prisma.transaction.findMany({
take: 100,
where: { status: "UNPROCESSED" },
});
// Loop through transactions and do stuff
for (const transaction of unprocessedTransactions) {
//stuff
}
} catch (e) {
// handle error
}
if (loopFlag === true) {
setTimeout(loop, 1000); //if flag changes, this will stop running
}
}
if (require.main === module) {
loop(); // This is called when server starts, but not when file is imported
}
La razón por la que uso setTimeout y no setInterval es porque pueden ocurrir muchos errores al procesar elementos recuperados de la base de datos. Estos errores, sin embargo, se solucionan esperando unos milisegundos. Entonces, el beneficio del patrón a continuación es que si ocurre un error, el bucle se reinicia inmediatamente y el error no aparecerá porque ha pasado un ms (se debe a problemas de concurrencia; ignoremos esto por ahora).
Para intentar iniciar y detener este ciclo, tengo un punto final que simplemente llama a la función loopFlagSwitch.
import { NextApiRequest, NextApiResponse } from "next";
import { loopFlagSwitch } from "services/loop";
async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
loopFlagSwitch(req.body.flag);
} catch (error) {
logger.info({ error: error });
}
}
export default handler;
El problema es que, incluso cuando se llama a este punto final, el ciclo setTimeout continúa. ¿Por qué no elige el cambio de bandera?
Lo que ha intentado funcionaría dentro de una página web normal, porque la variable loopFlag estaría en el ámbito global (ventana).
Next.js no comparte el alcance global de la misma manera. Por lo tanto, debe usar un contexto de reacción para compartir el acceso a la variable.
Mi sugerencia es introducir el uso de señales.
Un servicio como Pusher activará el evento que escuchará el procesador de transacciones.
su api/código de procesamiento de transacciones anterior o cualquier otro
Las acciones de señal como "iniciar" y "detener" se activarán en cualquier momento, incluso en producción, ya sea por la interfaz o a través del portal de inserción que se usará para cambiar el indicador de bucle a verdadero o falso.