Cómo comenzar rápidamente con VUE3.0: ingrese al aprendizaje
Después de que se lance nuestro servicio, inevitablemente será programado por el entorno en ejecución (como contenedores, pm2, etc.), las actualizaciones del servicio provocarán reinicios y varias excepciones provocarán. el proceso falla; en general, el entorno en ejecución tiene monitoreo de salud del proceso de servicio y reiniciará el proceso cuando el proceso sea anormal. Al actualizar, también existe una estrategia de actualización continua. Sin embargo, la estrategia de programación del entorno en ejecución trata nuestro proceso de servicio como una caja negra y no se preocupa por las condiciones internas de ejecución del proceso de servicio. Por lo tanto, nuestro proceso de servicio necesita detectar activamente las acciones de programación del entorno en ejecución y luego ejecutarlas. algunas acciones de limpieza de salida.
Por eso, hoy analizaremos las diversas situaciones que pueden provocar la salida del proceso Node.js y qué podemos hacer escuchando estos eventos de salida del proceso.
Principio:
cuando un proceso quiere salir, no hay más que dos situaciones, una es que el proceso sale activamente y la otra es que recibe una señal del sistema que requiere que el proceso salga.
Salida de notificación de señal del sistema
Las señales comunes del sistema se enumeran en el documento oficial de Node.js. Nos centramos principalmente en algunas:
Al recibir una señal de salida no forzada, el proceso de Node.js puede escuchar la señal de salida y realizar alguna lógica de salida personalizada. Por ejemplo, escribimos una herramienta cli que tarda mucho en ejecutar una tarea. Si el usuario desea salir del proceso mediante Ctrl+c antes de que se complete la tarea, se le puede pedir que espere:
const readline = require(' línea de lectura'); proceso.on('SIGNO', () => { // Usamos readline para implementar simplemente la interacción en la línea de comando const rl = readline.createInterface({ entrada: proceso.stdin, salida: proceso.stdout }); rl.question('La tarea aún no se ha completado, ¿está seguro de que desea salir?', respuesta => { si (respuesta === 'sí') { console.log('Ejecución de tarea interrumpida, proceso de salida'); proceso.salir(0); } demás { console.log('La tarea continúa...'); } rl.cerrar(); }); }); // Simula una tarea que tarda 1 minuto en ejecutarse const longTimeTask = () => { console.log('inicio de tarea...'); setTimeout(() => { console.log('fin de tarea'); }, 1000 * 60); }; longTimeTask();
El efecto es el siguiente. Cada vez que presione Ctrl + C, se le solicitará al usuario:
El proceso sale activamente
de Node.js. El proceso sale activamente, incluidas principalmente las siguientes situaciones:
Sabemos que pm2 tiene el efecto de un proceso demonio. En su caso, cuando su proceso sale con un error, pm2 reiniciará su proceso. proceso hijo en el modo de clúster de Node.js (en realidad, pm2 tiene una lógica similar):
const cluster = require('cluster'); const http = requerir('http'); const numCPUs = require('os').cpus().length; proceso constante = requerir('proceso'); //Código de proceso principal if (cluster.isMaster) { console.log(`Iniciar el proceso principal: ${process.pid}`); // Según la cantidad de núcleos de CPU, crea un proceso de trabajo para (let i = 0; i < numCPUs; i++) { cluster.fork(); } // Escuche el evento de salida del proceso de trabajo cluster.on('exit', (worker, code, signal) => { console.log(`Proceso de trabajo ${worker.process.pid} salió, código de error: ${código || señal}, reiniciando...`); //Reinicia el proceso hijo cluster.fork(); }); } // Código de proceso de trabajo if (cluster.isWorker) { // Escuche eventos de error no detectados process.on('uncaughtException', error => { console.log(`Se produjo un error en el proceso de trabajo ${process.pid}`, error); proceso.emit('desconectar'); proceso.salir(1); }); //Crear servidor web // Cada proceso de trabajo escuchará el puerto 8000 (Node.js lo manejará internamente y no causará conflictos de puerto) http.createServer((solicitud, res) => { res.writeHead(200); res.end('hola mundon'); }).escuchar(8000); console.log(`Iniciar proceso de trabajo: ${process.pid}`); }
Práctica de aplicación
Las diversas situaciones en las que el proceso Node.js sale se han analizado anteriormente. Ahora crearemos una herramienta para monitorear la salida del proceso. Cuando el proceso Node.js sale, el usuario puede ejecutar su propia lógica de salida.
// gancho de salida. //Guarde las tareas de salida que deben ejecutarse const task = []; //Agregar tarea de salida const addExitTask = fn => task.push(fn); const handleExit = (código, error) => { // ...la implementación de handleExit se muestra a continuación}; //Escuche varios eventos de salida Process.on('exit', code => handleExit(code)); // De acuerdo con las especificaciones POSIX, usamos 128 + número de señal para obtener el código de salida final // Consulte la imagen a continuación para ver el número de señal. Puede ejecutar kill -l en el sistema Linux para ver el proceso de todos los números de señal. ('SIGHUP', () => manejarSalir(128 + 1)); proceso.on('SIGINT', () => handleExit(128 + 2)); proceso.on('SIGTERM', () => handleExit(128 + 15)); // Presione ctrl+break para salir de la señal Process.on('SIGBREAK', () => handleExit(128 + 21)); // El código de salida 1 representa un error no detectado que provocó que el proceso saliera Process.on('uncaughtException', error => handleExit(1, error)); Process.on('unhandledRejection', error => handleExit(1, error))
;
A continuación, debemos implementar la función de salida del proceso real handleExit, debido a que la función de tarea pasada por el usuario puede ser sincrónica o asincrónica, podemos usar Process.nextTick para garantizar que se haya ejecutado el código de sincronización del usuario, lo que puede entenderse fácilmente como proceso; .nextTick se ejecutará después de que se complete la ejecución del código sincrónico en cada etapa del bucle de eventos (comprenda proceso.nextTick para tareas asincrónicas, necesitamos que el usuario llame a la devolución de llamada para decirnos que la tarea asincrónica se ha completado:
// Marcar si); está saliendo. Evite ejecuciones múltiples de let isExiting = false; const handleExit = (código, error) => { si (está saliendo) regresa; estáSaliendo = verdadero; // Marca que se ha realizado la acción de salida para evitar múltiples llamadas a let hasDoExit = fasle; const salir = () => { si (hasDoExit) regresa; hasDoExit = verdadero proceso.nextTick(() => proceso.salir(código)) } // Registra cuántas tareas asincrónicas hay let asyncTaskCount = 0; // Una vez finalizada la tarea asincrónica, la devolución de llamada que el usuario necesita llamar let ayncTaskCallback = () => { proceso.nextTick(() => { asyncTaskCount-- si (asyncTaskCount === 0) hacerSalir() }) } //Ejecutar todas las tareas de salida task.forEach(taskFn => { // Si el número de parámetros de la función taskFn es mayor que 1, se considera que se pasa el parámetro de devolución de llamada y es una tarea asincrónica if (taskFn.length > 1) { asyncTaskCount++ tareaFn(error, ayncTaskCallback) } demás { tareaFn(error) } }); // Si hay una tarea asincrónica if (asyncTaskCount > 0) { // Después de más de 10 segundos, fuerza la salida setTimeout(() => { hacerSalir(); }, 10 * 1000) } demás { hacerSalir() } };
En este punto, nuestra herramienta de monitoreo de salida de procesos está completa para la implementación completa, puede ver esta biblioteca de código abierto async-exit-hook
https://github.com/darukjs/daruk-exit-hook
. sale de
nuestro servidor web al reiniciar, ser programado por un contenedor en ejecución (pm2 o docker, etc.), o cuando ocurre una excepción y el proceso sale, esperamos realizar acciones de salida, como completar la respuesta a las solicitudes conectadas al. servicio, limpiar la conexión de la base de datos, imprimir registros de errores, activar alarmas, etc. Después de completar la acción de salida y luego salir del proceso, podemos usar la herramienta de monitoreo de salida del proceso en este momento para implementar:
const http = require(' http'); //Crear servidor web servidor constante = http.createServer((req, res) => { res.writeHead(200); res.end('hola mundon'); }).escuchar(8000); // Utilice la herramienta que desarrollamos anteriormente para agregar una tarea de salida de proceso addExitTask((error, callback) => { // Imprime registros de errores, activa alarmas, libera conexiones de bases de datos, etc. console.log('El proceso salió de forma anormal', error) // Deja de aceptar nuevas solicitudes server.close((error) => { si (error) { console.log('Error al dejar de aceptar nuevas solicitudes', error) } demás { console.log('Dejar de aceptar nuevas solicitudes') } }) // Un enfoque más simple es esperar un cierto período de tiempo (aquí esperamos 5 segundos) para que se completen las solicitudes existentes // Si desea asegurarse completamente de que se procesen todas las solicitudes, debe registrar cada conexión y esperar hasta todas las conexiones se liberan. Ejecute la acción de salida // Puede consultar la biblioteca de código abierto https://github.com/sebhildebrandt/http-graceful-shutdown. setTimout(devolución de llamada, 5 * 1000) })
Resumen
A través del texto anterior, creo que ya conoce las diversas situaciones que provocan la salida del proceso Node.js. Una vez que el servicio está en línea, aunque herramientas como k8s y pm2 pueden iniciar continuamente el proceso cuando el proceso sale anormalmente para garantizar la disponibilidad del servicio, también debemos detectar activamente la anomalía o programación del proceso en el código, para que para poder detectar problemas antes.