VUE3.0을 빠르게 시작하는 방법: 학습을 시작하세요.
서비스가 출시된 후에는 실행 환경(예: 컨테이너, pm2 등)에 의해 불가피하게 예약되며, 서비스 업그레이드로 인해 다시 시작되고 다양한 예외가 발생합니다. 일반적으로 실행 중인 환경에는 서비스 프로세스의 상태 모니터링이 있으며 프로세스가 비정상일 때 프로세스를 다시 시작합니다. 롤링 업그레이드 전략도 있습니다. 그러나 실행 중인 환경의 스케줄링 전략은 우리의 서비스 프로세스를 블랙박스로 취급하고 서비스 프로세스의 내부 실행 조건에는 신경 쓰지 않습니다. 따라서 우리의 서비스 프로세스는 실행 중인 환경의 스케줄링 작업을 적극적으로 감지하고 수행해야 합니다. 일부 종료 정리 작업.
그래서 오늘은 Node.js 프로세스가 종료될 수 있는 다양한 상황과 이러한 프로세스 종료 이벤트를 수신하여 수행할 수 있는 작업을 정리하겠습니다.
원리:
프로세스가 종료하려고 할 때 두 가지 상황 외에는 없습니다. 하나는 프로세스가 적극적으로 종료되는 것이고, 다른 하나는 프로세스 종료를 요구하는 시스템 신호를 수신하는 것입니다.
시스템 신호 알림 종료
일반적인 시스템 신호는 Node.js 공식 문서에 나열되어 있습니다.
비강제 종료 신호를 받으면 Node.js 프로세스는 종료 신호를 듣고 일부 사용자 정의 종료 논리를 수행할 수 있습니다. 예를 들어, 작업을 실행하는 데 오랜 시간이 걸리는 cli 도구를 작성했습니다. 작업이 완료되기 전에 사용자가 ctrl+c를 통해 프로세스를 종료하려는 경우 사용자에게 기다리라는 메시지가 표시될 수 있습니다.
const readline = require(' readline'); process.on('SIGINT', () => { // 명령줄에서 상호작용을 간단히 구현하기 위해 readline을 사용합니다. const rl = readline.createInterface({ 입력: process.stdin, 출력: process.stdout }); rl.question('작업이 아직 완료되지 않았습니다. 종료하시겠습니까?', 답변 => { if (대답 === '예') { console.log('작업 실행이 중단되어 프로세스 종료'); 프로세스.exit(0); } 또 다른 { console.log('작업 계속...'); } rl.close(); }); }); // 실행하는 데 1분이 걸리는 작업을 시뮬레이션합니다. const longTimeTask = () => { console.log('작업 시작...'); setTimeout(() => { console.log('작업 종료'); }, 1000 * 60); }; longTimeTask();
ctrl + c를 누를 때마다 다음과 같은 메시지가 표시됩니다.
프로세스는
Node.js를 적극적으로 종료합니다. 주로 다음 상황을 포함하여 프로세스가
pm2에는 데몬 프로세스의 효과가 있습니다. 귀하의 경우 프로세스가 오류로 종료되면 pm2는 데몬의 효과도 구현합니다. Node.js 클러스터 모드의 하위 프로세스(실제로 pm2도 비슷한 논리를 가짐):
const Cluster = require('cluster' ); const http = require('http'); const numCPUs = require('os').cpus().length; const 프로세스 = require('프로세스'); //주요 프로세스 코드 if (cluster.isMaster) { console.log(`메인 프로세스 시작: ${process.pid}`); // CPU 코어 수에 따라 (let i = 0; i < numCPUs; i++)에 대한 작업 프로세스를 만듭니다. 클러스터.포크(); } //작업자 프로세스 종료 이벤트 수신 Cluster.on('exit', (worker, code, signal) => { console.log(`작업자 프로세스 ${worker.process.pid} 종료, 오류 코드: ${code || signal}, 다시 시작 중...`); //자식 프로세스를 다시 시작합니다.cluster.fork(); }); } // 작업자 프로세스 코드 if (cluster.isWorker) { // 포착되지 않은 오류 이벤트 수신 process.on('uncaughtException', error => { console.log(`작업자 프로세스 ${process.pid}에서 오류가 발생했습니다`, error); process.emit('연결 끊기'); 프로세스.종료(1); }); //웹 서버 생성 // 각 작업자 프로세스는 포트 8000을 수신합니다(Node.js는 이를 내부적으로 처리하며 포트 충돌을 일으키지 않습니다). http.createServer((req, res) => { res.writeHead(200); res.end('안녕하세요 세계n'); }).listen(8000); console.log(`작업자 프로세스 시작: ${process.pid}`); }
애플리케이션 실습
위에서는 Node.js 프로세스가 종료되는 다양한 상황을 분석했습니다. 이제 Node.js 프로세스가 종료되면 사용자는 자체 종료 로직을 실행할 수 있습니다.
// 종료 후크.js //실행해야 할 종료 작업을 저장합니다. const task = []; //종료 작업 추가 const addExitTask = fn =>Tasks.push(fn); const handlerExit = (코드, 오류) => { // ...handleExit 구현은 아래와 같습니다.}; //다양한 종료 이벤트 수신 process.on('exit', code => handlerExit(code)); // POSIX 사양에 따르면 최종 종료 코드를 얻기 위해 128 + 신호 번호를 사용합니다. // 신호 번호는 아래 그림을 참조하십시오. Linux 시스템에서 kill -l을 실행하면 모든 신호 번호 프로세스를 볼 수 있습니다. ('SIGHUP', () => handlerExit(128 + 1)); process.on('SIGINT', () => handlerExit(128 + 2)); process.on('SIGTERM', () => handlerExit(128 + 15)); // ctrl+break를 눌러 신호를 종료합니다. process.on('SIGBREAK', () => handlerExit(128 + 21)); // 종료 코드 1은 프로세스가 종료되도록 하는 포착되지 않은 오류를 나타냅니다. process.on('uncaughtException', error => handlerExit(1, error)); process.on('unhandledRejection', error => handlerExit(1, error))
;
다음으로 사용자가 전달한 작업 함수는 동기식 또는 비동기식일 수 있으므로 실제 프로세스 종료 함수인 handlerExit를 구현해야 합니다. process.nextTick을 사용하여 사용자의 동기화 코드가 실행되었는지 확인할 수 있으며 이는 프로세스를 쉽게 이해할 수 있습니다. .nextTick은 각 이벤트 루프 단계에서 동기 코드 실행이 완료된 후에 실행됩니다(process.nextTick 이해). 비동기 작업의 경우 사용자가 콜백을 호출하여 비동기 작업이 완료되었음을 알려야 합니다
. 종료 중입니다. let isExiting = false를 여러 번 실행하지 마세요. const handlerExit = (코드, 오류) => { if (isExiting) 반환; isExiting = 사실; // 여러 번의 호출을 피하기 위해 종료 작업이 수행되었음을 표시합니다. let hasDoExit = fasle; const doExit = () => { if (hasDoExit) 반환; hasDoExit = 사실 process.nextTick(() => process.exit(코드)) } // 비동기 작업이 몇 개인지 기록합니다. let asyncTaskCount = 0; // 비동기 작업이 끝난 후 사용자가 호출해야 하는 콜백 let ayncTaskCallback = () => { process.nextTick(() => { asyncTaskCount-- if (asyncTaskCount === 0) doExit() }) } //모든 종료 작업을 실행합니다. task.forEach(taskFn => { // taskFn 함수의 매개변수 개수가 1보다 큰 경우 콜백 매개변수가 전달된 것으로 간주하여 비동기 작업인 것으로 간주합니다. if (taskFn.length > 1) { 비동기태스크카운트++ taskFn(오류, ayncTaskCallback) } 또 다른 { taskFn(오류) } }); // 비동기 작업이 있는 경우 if (asyncTaskCount > 0) { // 10초가 지나면 강제 종료 setTimeout(() => { doExit(); }, 10 * 1000) } 또 다른 { 종료() } };
이 시점에서 프로세스 종료 모니터링 도구가 완료되었습니다. 이 오픈 소스 라이브러리 async-exit-hook
https://github.com/darukjs/daruk-exit-hook을 볼 수 있습니다
.
다시 시작하거나
실행 중인 컨테이너(pm2 또는 docker 등)에 의해 예약되거나 예외가 발생하고 프로세스가 종료되면 연결된 요청에 대한 응답을 완료하는 등의 종료 작업을 수행하기를 바랍니다. 서비스, 데이터베이스 연결 정리, 오류 로그 인쇄, 경보 트리거 등을 수행합니다. 종료 작업을 완료한 후 프로세스를 종료한 후 지금 바로 프로세스 종료 모니터링 도구를 사용하여 구현할 수 있습니다.
const http = require(' http'); //웹 서버 생성 const 서버 = http.createServer((req, res) => { res.writeHead(200); res.end('안녕하세요 세계n'); }).listen(8000); // 위에서 개발한 도구를 사용하여 프로세스 종료 작업을 추가합니다. addExitTask((error, callback) => { // 오류 로그 인쇄, 알람 트리거, 데이터베이스 연결 해제 등 console.log('프로세스가 비정상적으로 종료되었습니다', error) // 새로운 요청 수락을 중지합니다. server.close((error) => { if (오류) { console.log('새 요청 수락 중지 오류', error) } 또 다른 { console.log('새 요청 수락 중지') } }) // 더 간단한 접근 방식은 기존 요청이 완료될 때까지 특정 시간(여기에서는 5초) 동안 기다리는 것입니다. // 모든 요청이 처리되었는지 완전히 확인하려면 각 연결을 기록하고 완료될 때까지 기다려야 합니다. 모든 연결이 해제됩니다. 종료 작업을 실행합니다. //오픈 소스 라이브러리 https://github.com/sebhildebrandt/http-graceful-shutdown을 참조할 수 있습니다. setTimeout(콜백, 5 * 1000) })
요약
위의 내용을 통해 여러분은 Node.js 프로세스가 종료되는 다양한 상황을 이미 알고 계실 것입니다. 서비스가 온라인 상태가 된 후 프로세스가 비정상적으로 종료될 때 k8s 및 pm2와 같은 도구는 서비스 가용성을 보장하기 위해 프로세스를 지속적으로 끌어올 수 있지만 코드에서 프로세스의 비정상성이나 일정을 적극적으로 감지해야 합니다. 문제를 더 일찍 잡을 수 있습니다.