
Como começar rapidamente com o VUE3.0: Entre no aprendizado
Depois que nosso serviço for lançado, ele será inevitavelmente agendado pelo ambiente em execução (como contêineres, pm2, etc.), as atualizações do serviço causarão reinicializações e várias exceções causarão. o processo trava; em geral, o ambiente em execução tem monitoramento de integridade do processo de serviço e reinicia o processo quando o processo é anormal. Durante a atualização, há também uma estratégia de atualização contínua. No entanto, a estratégia de agendamento do ambiente em execução trata nosso processo de serviço como uma caixa preta e não se preocupa com as condições internas de execução do processo de serviço. Portanto, nosso processo de serviço precisa detectar ativamente as ações de agendamento do ambiente em execução e então executar. algumas ações de limpeza de saída.
Portanto, hoje vamos resolver as várias situações que podem causar a saída do processo Node.js e o que podemos fazer ouvindo esses eventos de saída do processo.
Princípio:
Quando um processo deseja sair, não há nada mais do que duas situações: uma é que o processo sai ativamente e a outra é que ele recebe um sinal do sistema exigindo a saída do processo.
Saída de notificação de sinal do sistema
Sinais comuns do sistema estão listados no documento oficial do Node.js. Nós nos concentramos principalmente em alguns:
Ao receber um sinal de saída não forçado, o processo Node.js pode ouvir o sinal de saída e fazer alguma lógica de saída personalizada. Por exemplo, escrevemos uma ferramenta cli que leva muito tempo para executar uma tarefa. Se o usuário quiser sair do processo por meio de ctrl+c antes que a tarefa seja concluída, o usuário pode ser solicitado a esperar:
const readline = require(' linha de leitura');
process.on('SIGINT', () => {
// Usamos readline para simplesmente implementar a interação na linha de comando const rl = readline.createInterface({
entrada: process.stdin,
saída: process.stdout
});
rl.question('A tarefa ainda não foi concluída, tem certeza que deseja sair?', resposta => {
if (resposta === 'sim') {
console.log('Execução da tarefa interrompida, processo de saída');
processo.exit(0);
} outro {
console.log('A tarefa continua...');
}
rl.close();
});
});
//Simula uma tarefa que leva 1 minuto para ser executada const longTimeTask = () => {
console.log('início da tarefa...');
setTimeout(() => {
console.log('fim da tarefa');
}, 1000*60);
};
longTimeTask(); O efeito é o seguinte.

O processo sai ativamente
do Node.js O processo sai ativamente, incluindo principalmente as seguintes situações:
Sabemos que pm2 tem o efeito de um processo daemon. No seu caso, quando o seu processo termina com um erro, o pm2 também implementa o efeito de um daemon. processo filho no modo cluster do Node.js (na verdade, pm2 tem lógica semelhante):
const cluster = require('cluster' );
const http = requer('http');
const numCPUs = require('os').cpus().length;
const processo = require('processo');
//Código do processo principal if (cluster.isMaster) {
console.log(`Iniciar o processo principal: ${process.pid}`);
// Com base no número de núcleos da CPU, crie um processo de trabalho para (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
//Ouça o evento de saída do processo de trabalho cluster.on('exit', (worker, code, signal) => {
console.log(`Processo de trabalho ${worker.process.pid} encerrado, código de erro: ${código || sinal}, reiniciando...`);
//Reinicia o processo filho cluster.fork();
});
}
// Código do processo de trabalho if (cluster.isWorker) {
// Ouça eventos de erro não detectados process.on('uncaughtException', error => {
console.log(`Ocorreu um erro no processo de trabalho ${process.pid}`, erro);
process.emit('desconectar');
processo.exit(1);
});
//cria servidor web
// Cada processo de trabalho escutará a porta 8000 (o Node.js irá lidar com isso internamente e não causará conflitos de porta)
http.createServer((req, res) => {
res.writeHead(200);
res.end('olá mundon');
}).ouvir(8000);
console.log(`Iniciar processo de trabalho: ${process.pid}`);
} Prática de aplicação
As diversas situações em que o processo Node.js sai foram analisadas acima. Agora faremos uma ferramenta para monitorar a saída do processo. Quando o processo Node.js termina, o usuário tem permissão para executar sua própria lógica de saída.
//hook de saída.
//Salva as tarefas de saída que precisam ser executadas const tasks = [];
//Adicionar tarefa de saída const addExitTask = fn => tasks.push(fn);
const handleExit = (código, erro) => {
// ...a implementação do handleExit é mostrada abaixo};
//Ouvir vários eventos de saída process.on('exit', code => handleExit(code));
// De acordo com as especificações POSIX, usamos 128 + número do sinal para obter o código de saída final // Consulte a imagem abaixo para obter o número do sinal. Você pode executar kill -l no sistema Linux para visualizar todos os números de sinal process.on. ('SIGHUP', () => handleExit(128 + 1));
process.on('SIGINT', () => handleExit(128 + 2));
process.on('SIGTERM', () => handleExit(128 + 15));
// Pressione ctrl+break para sair do sinal process.on('SIGBREAK', () => handleExit(128 + 21));
// O código de saída 1 representa um erro não detectado que fez com que o processo fosse encerrado process.on('uncaughtException', error => handleExit(1, error));
process.on('unhandledRejection', error => handleExit(1, error)) ;

Em seguida, precisamos implementar a função real de saída do processo handleExit, porque a função de tarefa passada pelo usuário pode ser síncrona ou assíncrona, podemos usar process.nextTick para garantir que o código de sincronização do usuário foi executado, o que pode ser facilmente compreendido; .nextTick será executado após a conclusão da execução do código síncrono em cada estágio do loop de eventos (entenda process.nextTick); para tarefas assíncronas, precisamos que o usuário chame o retorno de chamada para nos informar que a tarefa assíncrona foi concluída:
// Marque se está saindo, evite múltiplas execuções de let isExiting = false;
const handleExit = (código, erro) => {
if (isExiting) retornar;
isExiting = verdadeiro;
// Marca que a ação de saída foi executada para evitar múltiplas chamadas para let hasDoExit = fasle;
const doExit = () => {
se (hasDoExit) retornar;
hasDoExit = verdadeiro
process.nextTick(() => process.exit(código))
}
// Registra quantas tarefas assíncronas existem let asyncTaskCount = 0;
// Após o término da tarefa assíncrona, o retorno de chamada que o usuário precisa chamar let ayncTaskCallback = () => {
process.nextTick(() => {
asyncTaskCount--
if (asyncTaskCount === 0) doExit()
})
}
//Executa todas as tarefas de saída task.forEach(taskFn => {
// Se o número de parâmetros da função taskFn for maior que 1, considera-se que o parâmetro callback foi passado e é uma tarefa assíncrona if (taskFn.length > 1) {
asyncTaskCount++
taskFn(erro, ayncTaskCallback)
} outro {
tarefaFn(erro)
}
});
// Se houver uma tarefa assíncrona if (asyncTaskCount > 0) {
// Depois de mais de 10s, forçar a saída setTimeout(() => {
doExit();
}, 10*1000)
} outro {
fazerSair()
}
}; Neste ponto, nossa ferramenta de monitoramento de saída de processo está concluída. Para a implementação completa, você pode visualizar esta biblioteca de código aberto async-exit-hook
https://github.com/darukjs/daruk-exit-hook
. sai do
nosso servidor web Ao reiniciar, sendo agendado por um contêiner em execução (pm2 ou docker, etc.), ou quando ocorre uma exceção e o processo termina, esperamos realizar ações de saída, como completar a resposta às solicitações conectadas ao. serviço, limpando a conexão do banco de dados, imprimindo logs de erros, acionando alarmes, etc., faça Depois de concluir a ação de saída e sair do processo, podemos usar a ferramenta de monitoramento de saída do processo agora mesmo para implementar:
const http = require(' http');
//cria servidor web
servidor const = http.createServer((req, res) => {
res.writeHead(200);
res.end('olá mundon');
}).ouvir(8000);
// Use a ferramenta que desenvolvemos acima para adicionar uma tarefa de saída do processo addExitTask((error, callback) => {
// Imprime logs de erros, aciona alarmes, libera conexões de banco de dados, etc. console.log('Processo encerrado anormalmente', erro)
// Pare de aceitar novas solicitações server.close((error) => {
se (erro) {
console.log('Erro ao parar de aceitar novas solicitações', erro)
} outro {
console.log('Parar de aceitar novas solicitações')
}
})
// Uma abordagem mais simples é esperar um certo período de tempo (aqui esperamos 5s) para que as solicitações existentes sejam concluídas // Se você deseja garantir completamente que todas as solicitações sejam processadas, você precisa registrar cada conexão e esperar até todas as conexões são liberadas. Execute a ação de saída // Você pode consultar a biblioteca de código aberto https://github.com/sebhildebrandt/http-graceful-shutdown
setTimout(retorno de chamada, 5 * 1000)
}) Resumo
Através do texto acima, acredito que você já esteja ciente das diversas situações que causam o encerramento do processo Node.js. Depois que o serviço estiver online, embora ferramentas como k8s e pm2 possam puxar continuamente o processo quando ele sai de forma anormal para garantir a disponibilidade do serviço, devemos também detectar ativamente a anormalidade ou agendamento do processo no código, de modo que para poder detectar problemas mais cedo.