Mari kita bincangkan tentang pelbagai situasi yang mungkin menyebabkan proses Node.js keluar

青灯夜游
Lepaskan: 2022-04-02 20:09:02
ke hadapan
3569 orang telah melayarinya

Artikel ini membincangkan tentang proses keluar Node dan memperkenalkan pelbagai situasi yang mungkin menyebabkan proses Node.js keluar. Saya harap ia akan membantu semua orang.

Mari kita bincangkan tentang pelbagai situasi yang mungkin menyebabkan proses Node.js keluar

Selepas perkhidmatan kami dikeluarkan, ia pasti akan dijadualkan oleh persekitaran operasi (seperti bekas, pm2, dll.), peningkatan perkhidmatan akan menyebabkan dimulakan semula, dan pelbagai pengecualian akan menyebabkan proses ranap; secara umum Seterusnya, persekitaran operasi mempunyai pemantauan kesihatan proses perkhidmatan Apabila proses tidak normal, proses akan dimulakan semula Apabila menaik taraf, terdapat juga strategi naik taraf. Walau bagaimanapun, strategi penjadualan persekitaran berjalan menganggap proses perkhidmatan kami sebagai kotak hitam dan tidak mengambil berat tentang keadaan berjalan dalaman proses perkhidmatan Oleh itu, proses perkhidmatan kami perlu secara aktif merasakan tindakan penjadualan persekitaran berjalan dan kemudian melaksanakan beberapa tindakan pembersihan keluar .

Jadi hari ini kita akan menyelesaikan pelbagai situasi yang mungkin menyebabkan proses Node.js keluar dan perkara yang boleh kita lakukan dengan mendengar peristiwa keluar proses ini.

Prinsip

Satu proses perlu keluar dalam dua situasi iaitu proses itu keluar atas inisiatifnya sendiri, dan satu lagi ialah itu ia menerima isyarat sistem Minta proses untuk keluar.

Pemberitahuan isyarat sistem untuk keluar

Isyarat sistem biasa disenaraikan dalam dokumen rasmi Node.js Kami memberi tumpuan terutamanya kepada beberapa:

  • SIGHUP: Daripada menghentikan proses melalui ctrl c, tetapi menutup terus terminal baris arahan, isyarat ini akan dicetuskan
  • SIGINT: Dicetuskan apabila ctrl c ditekan untuk menghentikan proses ; pm2 dimulakan semula atau dihentikan Apabila proses anak adalah proses anak, isyarat juga akan dihantar ke proses anak
  • SIGTERM: Biasanya digunakan untuk memberitahu proses untuk keluar dengan anggun Contohnya, apabila k8s memadamkan pod , ia akan menghantar isyarat SIGTERM ke pod Pod boleh berada dalam tempoh tamat masa (lalai 30s) Lakukan beberapa tindakan pembersihan keluar
  • SIGBREAK: Pada sistem tetingkap, menekan ctrl break akan mencetuskan isyarat ini
  • SIGKILL: Paksa untuk keluar dari proses, proses tidak boleh melakukan sebarang tindakan pembersihan, laksanakan perintah bunuh -9 pid, proses akan menerima isyarat ini. Apabila k8s memadamkan pod, jika ia mengambil masa lebih daripada 30 saat dan pod belum keluar, k8s akan menghantar isyarat SIGKILL ke pod dan segera keluar dari proses pod apabila pm2 dimulakan semula atau menghentikan proses, jika mengambil masa lebih daripada 1.6 saat dan proses belum keluar, ia juga akan menghantar isyarat SIGKILL

Apabila menerima isyarat keluar tanpa paksa, proses Node.js boleh mendengar isyarat keluar dan melakukan beberapa keluar tersuai. logik. Sebagai contoh, kami menulis alat cli yang mengambil masa yang lama untuk melaksanakan tugasan Jika pengguna ingin keluar dari proses melalui ctrl c sebelum tugasan selesai, pengguna boleh digesa untuk menunggu:

const readline = require('readline');

process.on('SIGINT', () => {
  // 我们通过 readline 来简单地实现命令行里面的交互
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });
  rl.question('任务还没执行完,确定要退出吗?', answer => {
    if (answer === 'yes') {
      console.log('任务执行中断,退出进程');
      process.exit(0);
    } else {
      console.log('任务继续执行...');
    }
    rl.close();
  });
});



// 模拟一个需要执行 1 分钟的任务
const longTimeTask = () => {
  console.log('task start...');
  setTimeout(() => {
    console.log('task end');
  }, 1000 * 60);
};

longTimeTask();
Salin selepas log masuk
<. 🎜> untuk mencapai kesan Seperti berikut, setiap kali ctrl c ditekan, pengguna akan digesa:

Mari kita bincangkan tentang pelbagai situasi yang mungkin menyebabkan proses Node.js keluar

Proses keluar secara aktif

Proses Node.js keluar secara aktif, terutamanya Termasuk situasi berikut:

    Ralat tidak ditangkap dicetuskan semasa pelaksanaan kod Anda boleh memantau situasi ini melalui process.on('uncaughtException')
  • Semasa pelaksanaan kod Penolakan janji yang tidak terurus dicetuskan (Node.js v16 akan menyebabkan proses keluar Anda boleh memantau situasi ini melalui process.on('unhandledRejection')
  • EventEmitter mencetuskan unlistened). acara ralat
  • Fungsi process.exit dipanggil secara aktif dalam kod untuk keluar dari proses Anda boleh memantaunya melalui process.on('exit')
  • Baris gilir acara Node.js. kosong. Anda hanya boleh berfikir bahawa tiada kod yang perlu dilaksanakan Anda boleh memantaunya melalui process.on('exit')
Kami tahu bahawa pm2 mempunyai kesan daemon. proses. Apabila proses anda keluar dengan ralat, pm2 akan memulakan semula proses anda. ):

const cluster = require(&#39;cluster&#39;);
const http = require(&#39;http&#39;);
const numCPUs = require(&#39;os&#39;).cpus().length;
const process = require(&#39;process&#39;);

// 主进程代码
if (cluster.isMaster) {
  console.log(`启动主进程: ${process.pid}`);
  // 根据 cpu 核数,创建工作进程
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  // 监听工作进程退出事件
  cluster.on(&#39;exit&#39;, (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 退出,错误码: ${code || signal}, 重启中...`);
    // 重启子进程
    cluster.fork();
  });
}

// 工作进程代码
if (cluster.isWorker) {
  // 监听未捕获错误事件
  process.on(&#39;uncaughtException&#39;, error => {
    console.log(`工作进程 ${process.pid} 发生错误`, error);
    process.emit(&#39;disconnect&#39;);
    process.exit(1);
  });
  // 创建 web server
  // 各个工作进程都会监听端口 8000(Node.js 内部会做处理,不会导致端口冲突)
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(&#39;hello world\n&#39;);
  }).listen(8000);
  console.log(`启动工作进程: ${process.pid}`);
}
Salin selepas log masuk
Amalan aplikasi

Di atas telah menganalisis pelbagai situasi proses keluar Node.js untuk memantau proses keluar. Apabila proses Node.js keluar, pengguna dibenarkan untuk melaksanakan logik keluarnya sendiri:

Nombor isyarat:

// exit-hook.js
// 保存需要执行的退出任务
const tasks = [];
// 添加退出任务
const addExitTask = fn => tasks.push(fn);
const handleExit = (code, error) => {  
  // ...handleExit 的实现见下面
};
// 监听各种退出事件
process.on(&#39;exit&#39;, code => handleExit(code));
// 按照 POSIX 的规范,我们用 128 + 信号编号 得到最终的退出码
// 信号编号参考下面的图片,大家可以在 linux 系统下执行 kill -l 查看所有的信号编号
process.on(&#39;SIGHUP&#39;, () => handleExit(128 + 1));
process.on(&#39;SIGINT&#39;, () => handleExit(128 + 2));
process.on(&#39;SIGTERM&#39;, () => handleExit(128 + 15));
// windows 下按下 ctrl+break 的退出信号
process.on(&#39;SIGBREAK&#39;, () => handleExit(128 + 21));
// 退出码 1 代表未捕获的错误导致进程退出
process.on(&#39;uncaughtException&#39;, error => handleExit(1, error));
process.on(&#39;unhandledRejection&#39;, error => handleExit(1, error));
Salin selepas log masuk

接下来我们要实现真正的进程退出函数 handleExit,因为用户传入的任务函数可能是同步的,也可能是异步的;我们可以借助 process.nextTick 来保证用户的同步代码都已经执行完成,可以简单理解 process.nextTick 会在每个事件循环阶段的同步代码执行完成后执行(理解 process.nextTick);针对异步任务,我们需要用户调用 callback 来告诉我们异步任务已经执行完成了:

// 标记是否正在退出,避免多次执行
let isExiting = false;
const handleExit = (code, error) => {
  if (isExiting) return;
  isExiting = true;

  // 标记已经执行了退出动作,避免多次调用
  let hasDoExit = fasle;
  const doExit = () => {
      if (hasDoExit) return;
      hasDoExit = true
      process.nextTick(() => process.exit(code))
  }

  // 记录有多少个异步任务
  let asyncTaskCount = 0;
  // 异步任务结束后,用户需要调用的回调
  let ayncTaskCallback = () => {
      process.nextTick(() => {
        asyncTaskCount--
        if (asyncTaskCount === 0) doExit() 
      })
  }
  // 执行所有的退出任务

  tasks.forEach(taskFn => {
      // 如果 taskFn 函数的参数个数大于 1,认为传递了 callback 参数,是一个异步任务
      if (taskFn.length > 1) {
         asyncTaskCount++
         taskFn(error, ayncTaskCallback)
      } else {
          taskFn(error)
      }
  });

  // 如果存在异步任务
  if (asyncTaskCount > 0) {
      // 超过 10s 后,强制退出
      setTimeout(() => {
          doExit();
      }, 10 * 1000)
  } else {
      doExit()
  }
};
Salin selepas log masuk

至此,我们的进程退出监听工具就完成了,完整的实现可以查看这个开源库 async-exit-hook

https://github.com/darukjs/daruk-exit-hook

进程优雅退出

通常我们的 web server 在重启、被运行容器调度(pm2 或者 docker 等)、出现异常导致进程退出时,我们希望执行退出动作,如完成已经连接到服务的请求响应、清理数据库连接、打印错误日志、触发告警等,做完退出动作后,再退出进程,我们可以使用刚才的进程退出监听工具实现:

const http = require(&#39;http&#39;);

// 创建 web server
const server = http.createServer((req, res) => {
  res.writeHead(200);
  res.end(&#39;hello world\n&#39;);
}).listen(8000);

// 使用我们在上面开发的工具添加进程退出任务
addExitTask((error, callback) => {
   // 打印错误日志、触发告警、释放数据库连接等
   console.log(&#39;进程异常退出&#39;, error)
   // 停止接受新的请求
   server.close((error) => {
       if (error) {
         console.log(&#39;停止接受新请求错误&#39;, error)
       } else {
         console.log(&#39;已停止接受新的请求&#39;)
       }
   })
   // 比较简单的做法是,等待一定的时间(这里我们等待 5s),让存量请求执行完毕
   // 如果要完全保证所有请求都处理完毕,需要记录每一个连接,在所有连接都释放后,才执行退出动作
   // 可以参考开源库 https://github.com/sebhildebrandt/http-graceful-shutdown
   setTimout(callback, 5 * 1000)
})
Salin selepas log masuk

总结

通过上面的文字,相信你已经对导致 Node.js 进程退出的各种情况心里有数了。在服务上线后,虽然 k8s、pm2 等工具能够在进程异常退出时,不停地拉起进程,保证服务的可用性,但我们也应该在代码中主动感知进程的异常或者被调度的情况,从而能够更早发现问题。

更多node相关知识,请访问:nodejs 教程

Atas ialah kandungan terperinci Mari kita bincangkan tentang pelbagai situasi yang mungkin menyebabkan proses Node.js keluar. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:juejin.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan