index.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /**!
  2. * cfork - index.js
  3. *
  4. * Copyright(c) fengmk2 and other contributors.
  5. * MIT Licensed
  6. *
  7. * Authors:
  8. * fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
  9. */
  10. 'use strict';
  11. /**
  12. * Module dependencies.
  13. */
  14. var cluster = require('cluster');
  15. var os = require('os');
  16. var util = require('util');
  17. var defer = global.setImmediate || process.nextTick;
  18. module.exports = fork;
  19. /**
  20. * cluster fork
  21. * @param {Object} options
  22. * - {String} exec exec file path
  23. * - {Number} count worker num, defualt to `os.cpus().length`
  24. * - {Boolean} refork refork when disconect and unexpected exit, default to `true`
  25. * @return {Cluster}
  26. */
  27. function fork(options) {
  28. if (cluster.isWorker) {
  29. return;
  30. }
  31. options = options || {};
  32. var exec = options.exec;
  33. var count = options.count || os.cpus().length;
  34. var refork = options.refork !== false;
  35. if (exec) {
  36. cluster.setupMaster({
  37. exec: exec
  38. });
  39. }
  40. var disconnects = {};
  41. var disconnectCount = 0;
  42. var unexpectedCount = 0;
  43. cluster.on('disconnect', function (worker) {
  44. disconnectCount++;
  45. disconnects[worker.process.pid] = new Date();
  46. refork && cluster.fork();
  47. });
  48. cluster.on('exit', function (worker, code, signal) {
  49. if (disconnects[worker.process.pid]) {
  50. delete disconnects[worker.process.pid];
  51. // worker disconnect first, exit expected
  52. return;
  53. }
  54. unexpectedCount++;
  55. refork && cluster.fork();
  56. cluster.emit('unexpectedExit', worker, code, signal);
  57. });
  58. // defer to set the listeners
  59. // so you can listen this by your own
  60. defer(function () {
  61. if (process.listeners('uncaughtException').length === 0) {
  62. process.on('uncaughtException', onerror);
  63. }
  64. if (cluster.listeners('unexpectedExit').length === 0) {
  65. cluster.on('unexpectedExit', onUnexpected);
  66. }
  67. });
  68. for (var i = 0; i < count; i++) {
  69. cluster.fork();
  70. }
  71. return cluster;
  72. /**
  73. * uncaughtException default handler
  74. */
  75. function onerror(err) {
  76. console.error('[%s] [cfork:master:%s] master uncaughtException: %s', Date(), process.pid, err.stack);
  77. console.error(err);
  78. console.error('(total %d disconnect, %d unexpected exit)', disconnectCount, unexpectedCount);
  79. }
  80. /**
  81. * unexpectedExit default handler
  82. */
  83. function onUnexpected(worker, code, signal) {
  84. var exitCode = worker.process.exitCode;
  85. var err = new Error(util.format('worker:%s died unexpected (code: %s, signal: %s, suicide: %s, state: %s)',
  86. worker.process.pid, exitCode, signal, worker.suicide, worker.state));
  87. err.name = 'WorkerDiedUnexpectedError';
  88. console.error('[%s] [cfork:master:%s] (total %d disconnect, %d unexpected exit) %s',
  89. Date(), process.pid, disconnectCount, unexpectedCount, err.stack);
  90. }
  91. }