Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

index.js 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. var spawn = require("child_process").spawn;
  2. var async = require("../../js/async");
  3. exports.start = start;
  4. exports.stop = stop;
  5. exports.event = event;
  6. var conf;
  7. var logger;
  8. var modules;
  9. class Process {
  10. constructor(id, cmd, options) {
  11. this.id = id;
  12. this.restart = options.restart;
  13. this.stopping = false;
  14. this.running = false;
  15. this.restarts = 0;
  16. this.name = cmd[0];
  17. cmd.shift();
  18. this.args = cmd;
  19. this.childOpts = {
  20. env: options.env,
  21. cwd: options.cwd,
  22. };
  23. this.info = logger.info.bind(logger, this.id+":");
  24. this.warn = logger.warn.bind(logger, this.id+":");
  25. }
  26. logOutput(stream, data) {
  27. data.toString()
  28. .split("\n")
  29. .map(line => line.trim())
  30. .forEach(line => {
  31. if (line === "") return;
  32. this.info(stream+":", line);
  33. });
  34. }
  35. onexit() {
  36. if (!this.restart)
  37. return;
  38. if (this.restarts < 2) {
  39. this.restarts += 1;
  40. var restarts = this.restarts;
  41. this.info("Restarting in 2 seconds.");
  42. setTimeout(() => {
  43. this.start();
  44. this.restarts = restarts;
  45. }, 2000);
  46. } else {
  47. this.warn("Not restarting anymore after 2 restarts.");
  48. }
  49. }
  50. start() {
  51. this.stopping = false;
  52. this.running = true;
  53. this.restarts = 0;
  54. this.child = spawn(this.name, this.args, this.childOpts);
  55. this.child.stdout.on("data",
  56. d => this.logOutput("stdout", d));
  57. this.child.stderr.on("data",
  58. d => this.logOutput("stderr", d));
  59. this.child.once("error", err => {
  60. if (!this.stopping)
  61. this.warn("Failed to start:", err);
  62. this.onexit();
  63. });
  64. this.child.once("close", code => {
  65. this.running = false;
  66. if (this.stopping)
  67. return;
  68. if (code === 0)
  69. this.info("Exited with status code 0");
  70. else
  71. this.warn("Exited with status code", code);
  72. this.onexit();
  73. });
  74. }
  75. stop(cb) {
  76. this.stopping = true;
  77. if (!this.running)
  78. return cb();
  79. this.info("Sending SIGTERM.");
  80. this.child.kill("SIGTERM");
  81. setTimeout(() => {
  82. if (this.running) {
  83. this.info("Sending SIGKILL.");
  84. this.child.kill("SIGKILL");
  85. }
  86. cb();
  87. }, 1000);
  88. }
  89. }
  90. class ProcessGroup {
  91. constructor(id, cmds, options) {
  92. this.procs = [];
  93. cmds.forEach(cmd => {
  94. var name = cmd[0];
  95. this.procs.push(new Process(id+"("+name+")", cmd, options));
  96. });
  97. }
  98. start() {
  99. this.procs.forEach(p => p.start());
  100. }
  101. stop(cb) {
  102. var next = async(this.procs.length, cb);
  103. this.procs.forEach(p => p.stop(next));
  104. }
  105. }
  106. var procs = {};
  107. function start(conf_, logger_, modules_) {
  108. conf = conf_ || conf;
  109. logger = logger_ || logger;
  110. modules = modules_ || modules;
  111. conf.forEach(proc => {
  112. if (procs[proc.name])
  113. return logger.warn("Igonring duplicate process: "+proc.name);
  114. var env = null;
  115. if (proc.env) {
  116. env = {};
  117. for (var i in process.env) {
  118. env[i] = process.env[i];
  119. }
  120. for (var i in proc.env) {
  121. env[i] = proc.env[i];
  122. }
  123. }
  124. var opts = {
  125. cwd: proc.in,
  126. env: env,
  127. restart: !!proc.restart,
  128. };
  129. var p;
  130. if (!proc.as || proc.as === "process") {
  131. p = new Process(proc.name, proc.run, opts);
  132. } else if (proc.as === "group") {
  133. p = new ProcessGroup(proc.name, proc.run, opts);
  134. } else {
  135. return logger.warn(
  136. proc.name+":",
  137. "Invalid 'as' attribute:",
  138. proc.as);
  139. }
  140. p.start();
  141. procs[proc.name] = p;
  142. });
  143. }
  144. function stop(cb) {
  145. var keys = Object.keys(procs);
  146. var next = async(keys.length, cb);
  147. keys.forEach(i => procs[i].stop(next));
  148. }
  149. function event(name, ...params) {
  150. switch (name) {
  151. default:
  152. logger.warn("Unknown event: "+name);
  153. }
  154. }