AsyncExit.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. let instance = null;
  2. const defaultTimeout = 15*1000;//15 sec
  3. const exitSignals = ['SIGINT', 'SIGTERM', 'SIGBREAK', 'SIGHUP', 'uncaughtException'];
  4. //singleton
  5. class AsyncExit {
  6. constructor(signals = exitSignals, codeOnSignal = 2) {
  7. if (!instance) {
  8. this.onSignalCallbacks = new Map();
  9. this.callbacks = new Map();
  10. this.afterCallbacks = new Map();
  11. this.exitTimeout = defaultTimeout;
  12. this._init(signals, codeOnSignal);
  13. instance = this;
  14. }
  15. return instance;
  16. }
  17. _init(signals, codeOnSignal) {
  18. const runSingalCallbacks = async(signal, err, origin) => {
  19. for (const signalCallback of this.onSignalCallbacks.keys()) {
  20. try {
  21. await signalCallback(signal, err, origin);
  22. } catch(e) {
  23. console.error(e);
  24. }
  25. }
  26. };
  27. for (const signal of signals) {
  28. process.once(signal, async(err, origin) => {
  29. await runSingalCallbacks(signal, err, origin);
  30. this.exit(codeOnSignal);
  31. });
  32. }
  33. }
  34. onSignal(signalCallback) {
  35. if (!this.onSignalCallbacks.has(signalCallback)) {
  36. this.onSignalCallbacks.set(signalCallback, true);
  37. }
  38. }
  39. add(exitCallback) {
  40. if (!this.callbacks.has(exitCallback)) {
  41. this.callbacks.set(exitCallback, true);
  42. }
  43. }
  44. addAfter(exitCallback) {
  45. if (!this.afterCallbacks.has(exitCallback)) {
  46. this.afterCallbacks.set(exitCallback, true);
  47. }
  48. }
  49. remove(exitCallback) {
  50. if (this.callbacks.has(exitCallback)) {
  51. this.callbacks.delete(exitCallback);
  52. }
  53. if (this.afterCallbacks.has(exitCallback)) {
  54. this.afterCallbacks.delete(exitCallback);
  55. }
  56. }
  57. setExitTimeout(timeout) {
  58. this.exitTimeout = timeout;
  59. }
  60. exit(code = 0) {
  61. if (this.exiting)
  62. return;
  63. this.exiting = true;
  64. const timer = setTimeout(() => { process.exit(code); }, this.exitTimeout);
  65. (async() => {
  66. for (const exitCallback of this.callbacks.keys()) {
  67. try {
  68. await exitCallback();
  69. } catch(e) {
  70. console.error(e);
  71. }
  72. }
  73. for (const exitCallback of this.afterCallbacks.keys()) {
  74. try {
  75. await exitCallback();
  76. } catch(e) {
  77. console.error(e);
  78. }
  79. }
  80. clearTimeout(timer);
  81. //console.log('Exited gracefully');
  82. process.exit(code);
  83. })();
  84. }
  85. }
  86. module.exports = AsyncExit;