index.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. 'use strict';
  2. const cluster = require('cluster');
  3. const getExitFunction = require('./exit');
  4. const init = Symbol('graceful-process-init');
  5. module.exports = (options = {}) => {
  6. const logger = options.logger || console;
  7. let logLevel = (options.logLevel || 'info').toLowerCase();
  8. if (logger !== console) {
  9. // don't handle custom logger level
  10. logLevel = 'info';
  11. }
  12. const printLogLevels = {
  13. info: true,
  14. warn: true,
  15. error: true,
  16. };
  17. if (logLevel === 'warn') {
  18. printLogLevels.info = false;
  19. } else if (logLevel === 'error') {
  20. printLogLevels.info = false;
  21. printLogLevels.warn = false;
  22. }
  23. const label = options.label || `graceful-process#${process.pid}`;
  24. if (process[init]) {
  25. printLogLevels.warn && logger.warn('[%s] graceful-process init already', label);
  26. return;
  27. }
  28. process[init] = true;
  29. const exit = getExitFunction(options.beforeExit, logger, label);
  30. // https://github.com/eggjs/egg-cluster/blob/master/lib/agent_worker.js#L35
  31. // exit gracefully
  32. process.once('SIGTERM', () => {
  33. printLogLevels.info && logger.info('[%s] receive signal SIGTERM, exiting with code:0', label);
  34. exit(0);
  35. });
  36. process.once('exit', code => {
  37. const level = code === 0 ? 'info' : 'error';
  38. printLogLevels[level] && logger[level]('[%s] exit with code:%s', label, code);
  39. });
  40. if (cluster.worker) {
  41. // cluster mode
  42. // https://github.com/nodejs/node/blob/6caf1b093ab0176b8ded68a53ab1ab72259bb1e0/lib/internal/cluster/child.js#L28
  43. cluster.worker.once('disconnect', () => {
  44. // ignore suicide disconnect event
  45. if (cluster.worker.exitedAfterDisconnect) return;
  46. logger.error('[%s] receive disconnect event in cluster fork mode, exitedAfterDisconnect:false', label);
  47. });
  48. } else {
  49. // child_process mode
  50. process.once('disconnect', () => {
  51. // wait a loop for SIGTERM event happen
  52. setImmediate(() => {
  53. // if disconnect event emit, maybe master exit in accident
  54. logger.error('[%s] receive disconnect event on child_process fork mode, exiting with code:110', label);
  55. exit(110);
  56. });
  57. });
  58. }
  59. };