Comment démarrer rapidement avec VUE3.0 : entrez dans l'apprentissage.
Une fois notre service publié, il sera inévitablement planifié par l'environnement d'exécution (tel que les conteneurs, pm2, etc.), les mises à niveau du service entraîneront des redémarrages et diverses exceptions. le processus tombe en panne; en général, l'environnement en cours d'exécution dispose d'une surveillance de l'état du processus de service qui redémarrera le processus lorsque le processus est anormal. Lors de la mise à niveau, il existe également une stratégie de mise à niveau continue. Cependant, la stratégie de planification de l'environnement d'exécution traite notre processus de service comme une boîte noire et ne se soucie pas des conditions d'exécution internes du processus de service. Par conséquent, notre processus de service doit détecter activement les actions de planification de l'environnement d'exécution, puis les exécuter. certaines actions de nettoyage de sortie.
Aujourd'hui, nous allons donc trier les différentes situations pouvant entraîner la fermeture du processus Node.js et ce que nous pouvons faire en écoutant ces événements de sortie de processus.
Principe :
lorsqu'un processus veut se terminer, il n'y a que deux situations. L'une est que le processus se termine activement et l'autre est qu'il reçoit un signal système exigeant que le processus se termine.
Sortie de notification du signal système
Les signaux système courants sont répertoriés dans le document officiel de Node.js. Nous nous concentrons principalement sur quelques-uns :
Lors de la réception d'un signal de sortie non forcé, le processus Node.js peut écouter le signal de sortie et effectuer une logique de sortie personnalisée. Par exemple, nous avons écrit un outil cli qui prend beaucoup de temps pour exécuter une tâche. Si l'utilisateur souhaite quitter le processus via ctrl+c avant que la tâche ne soit terminée, l'utilisateur peut être invité à attendre :
const readline = require(' lire la ligne'); processus.on('SIGINT', () => { // Nous utilisons readline pour implémenter simplement l'interaction dans la ligne de commande const rl = readline.createInterface({ entrée : process.stdin, sortie : process.stdout }); rl.question('La tâche n'est pas encore terminée, êtes-vous sûr de vouloir quitter ?', réponse => { si (réponse === 'oui') { console.log('Exécution de la tâche interrompue, processus de sortie'); processus.exit(0); } autre { console.log('La tâche continue...'); } rl.close(); }); }); // Simuler une tâche qui prend 1 minute pour s'exécuter const longTimeTask = () => { console.log('démarrage de la tâche...'); setTimeout(() => { console.log('fin de la tâche'); }, 1000 * 60); } ; longTimeTask();
L'effet est le suivant. Chaque fois que ctrl + c est enfoncé, l'utilisateur sera invité :
Le processus quitte activement
Node.js. Le processus se termine activement, notamment dans les situations suivantes :
Nous savons que pm2 a l'effet d'un processus démon. Dans votre cas, lorsque votre processus se termine avec une erreur, pm2 redémarrera votre processus. processus enfant en mode cluster de Node.js (en fait pm2 a une logique similaire) :
const cluster = require('cluster' ); const http = exiger('http'); const numCPUs = require('os').cpus().length; const processus = require('processus'); //Code du processus principal if (cluster.isMaster) { console.log(`Démarrer le processus principal : ${process.pid}`); // En fonction du nombre de cœurs de processeur, créez un processus de travail pour (let i = 0; i < numCPUs; i++) { cluster.fork(); } //Écoutez l'événement de sortie du processus de travail cluster.on('exit', (worker, code, signal) => { console.log(`Processus de travail ${worker.process.pid} quitté, code d'erreur : ${code || signal}, redémarrage...`); //Redémarrez le processus enfant cluster.fork(); }); } // Code du processus de travail if (cluster.isWorker) { // Écoutez les événements d'erreur non détectés process.on('uncaughtException', error => { console.log(`Une erreur s'est produite dans le processus de travail ${process.pid}`, erreur); process.emit('déconnecter'); processus.exit(1); }); //Créer un serveur web // Chaque processus de travail écoutera le port 8000 (Node.js le gérera en interne et ne provoquera pas de conflits de port) http.createServer((req, res) => { res.writeHead(200); res.end('bonjour tout le monden'); }).écouter(8000); console.log(`Démarrer le processus de travail : ${process.pid}`); }
Pratique d'application
Les différentes situations dans lesquelles le processus Node.js se termine ont été analysées ci-dessus. Nous allons maintenant créer un outil pour surveiller la sortie du processus. Lorsque le processus Node.js se termine, l'utilisateur est autorisé à exécuter sa propre logique de sortie :
// crochet de sortie js. //Enregistrez les tâches de sortie qui doivent être exécutées const tâches = []; //Ajouter une tâche de sortie const addExitTask = fn => tâches.push(fn); const handleExit = (code, erreur) => { // ...l'implémentation de handleExit est illustrée ci-dessous} ; //Écoutez divers événements de sortie process.on('exit', code => handleExit(code)); // Selon les spécifications POSIX, nous utilisons 128 + numéro de signal pour obtenir le code de sortie final // Veuillez vous référer à l'image ci-dessous pour le numéro de signal. Vous pouvez exécuter kill -l sous le système Linux pour afficher tous les numéros de signal process.on. ('SIGHUP', () => handleExit(128 + 1)); process.on('SIGINT', () => handleExit(128 + 2)); process.on('SIGTERM', () => handleExit(128 + 15)); // Appuyez sur ctrl+break pour quitter le signal process.on('SIGBREAK', () => handleExit(128 + 21)); // Le code de sortie 1 représente une erreur non détectée qui a provoqué la sortie du processus process.on('uncaughtException', error => handleExit(1, error)); process.on('unhandledRejection', error => handleExit(1, error));
Numéro de signal :
Ensuite, nous devons implémenter la véritable fonction de sortie de processus handleExit, car la fonction de tâche transmise par l'utilisateur peut être synchrone ou asynchrone, nous pouvons utiliser process.nextTick pour garantir que le code de synchronisation de l'utilisateur a été exécuté, ce qui peut être facilement compris par le processus ; .nextTick sera exécuté une fois l'exécution du code synchrone dans chaque étape de la boucle d'événement terminée (comprenez process.nextTick) ; pour les tâches asynchrones, nous avons besoin que l'utilisateur appelle le rappel pour nous dire que la tâche asynchrone est terminée :
// Marquez si il est en cours de sortie, évitez les exécutions multiples de let isExiting = false ; const handleExit = (code, erreur) => { si (isExiting) retourne ; estExiting = vrai ; // Marque que l'action de sortie a été effectuée pour éviter plusieurs appels à let hasDoExit = fasle; const doExit = () => { si (hasDoExit) retourne ; hasDoExit = vrai processus.nextTick(() => processus.exit(code)) } // Enregistrez le nombre de tâches asynchrones disponibles let asyncTaskCount = 0; // Une fois la tâche asynchrone terminée, le rappel que l'utilisateur doit appeler let ayncTaskCallback = () => { processus.nextTick(() => { asyncTaskCount-- si (asyncTaskCount === 0) doExit() }) } //Exécuter toutes les tâches de sortie tâches.forEach(taskFn => { // Si le nombre de paramètres de la fonction taskFn est supérieur à 1, on considère que le paramètre de rappel est passé et c'est une tâche asynchrone if (taskFn.length > 1) { asyncTaskCount++ taskFn (erreur, ayncTaskCallback) } autre { tâcheFn (erreur) } }); // S'il existe une tâche asynchrone if (asyncTaskCount > 0) { // Après plus de 10 s, forcez la sortie setTimeout(() => { doExit(); }, 10 * 1000) } autre { faireSortie() } } ;
À ce stade, notre outil de surveillance des sorties de processus est terminé. Pour la mise en œuvre complète, vous pouvez visualiser cette bibliothèque open source async-exit-hook
https://github.com/darukjs/daruk-exit-hook
Le processus
.quitte
notre serveur Web. Lors du redémarrage, étant planifié par un conteneur en cours d'exécution (pm2 ou docker, etc.), ou lorsqu'une exception se produit et que le processus se termine, nous espérons effectuer des actions de sortie, comme compléter la réponse aux requêtes connectées au serveur Web. service, nettoyer la connexion à la base de données, imprimer les journaux d'erreurs, déclencher des alarmes, etc., faites Après avoir terminé l'action de sortie, puis quitté le processus, nous pouvons utiliser l'outil de surveillance de sortie de processus tout à l'heure pour implémenter :
const http = require(' http'); //Créer un serveur web const serveur = http.createServer((req, res) => { res.writeHead(200); res.end('bonjour tout le monden'); }).écouter(8000); // Utilisez l'outil que nous avons développé ci-dessus pour ajouter une tâche de sortie de processus addExitTask((error, callback) => { // Imprimer les journaux d'erreurs, déclencher des alarmes, libérer les connexions à la base de données, etc. console.log('Le processus s'est terminé anormalement', erreur) // Arrêtez d'accepter de nouvelles requêtes server.close((erreur) => { si (erreur) { console.log('Erreur Arrêter d'accepter de nouvelles requêtes', erreur) } autre { console.log('Arrêtez d'accepter de nouvelles demandes') } }) // Une approche plus simple consiste à attendre un certain temps (ici nous attendons 5 secondes) pour que les requêtes existantes soient complétées // Si vous souhaitez vous assurer complètement que toutes les requêtes sont traitées, vous devez enregistrer chaque connexion et attendre que toutes les connexions sont libérées. Exécutez l'action de sortie // Vous pouvez vous référer à la bibliothèque open source https://github.com/sebhildebrandt/http-graceful-shutdown. setTimout(rappel, 5 * 1000) })
Résumé
À travers le texte ci-dessus, je pense que vous êtes déjà au courant des différentes situations qui provoquent la fermeture du processus Node.js. Une fois le service en ligne, bien que des outils tels que k8s et pm2 puissent continuellement relancer le processus lorsque le processus se termine anormalement pour garantir la disponibilité du service, nous devons également détecter activement l'anomalie ou la planification du processus dans le code, afin que pour pouvoir détecter les problèmes plus tôt.