processChild.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. 'use strict';
  2. var _types = require('../types');
  3. function _objectSpread(target) {
  4. for (var i = 1; i < arguments.length; i++) {
  5. var source = arguments[i] != null ? arguments[i] : {};
  6. var ownKeys = Object.keys(source);
  7. if (typeof Object.getOwnPropertySymbols === 'function') {
  8. ownKeys = ownKeys.concat(
  9. Object.getOwnPropertySymbols(source).filter(function(sym) {
  10. return Object.getOwnPropertyDescriptor(source, sym).enumerable;
  11. })
  12. );
  13. }
  14. ownKeys.forEach(function(key) {
  15. _defineProperty(target, key, source[key]);
  16. });
  17. }
  18. return target;
  19. }
  20. function _defineProperty(obj, key, value) {
  21. if (key in obj) {
  22. Object.defineProperty(obj, key, {
  23. value: value,
  24. enumerable: true,
  25. configurable: true,
  26. writable: true
  27. });
  28. } else {
  29. obj[key] = value;
  30. }
  31. return obj;
  32. }
  33. let file = null;
  34. let setupArgs = [];
  35. let initialized = false;
  36. /**
  37. * This file is a small bootstrapper for workers. It sets up the communication
  38. * between the worker and the parent process, interpreting parent messages and
  39. * sending results back.
  40. *
  41. * The file loaded will be lazily initialized the first time any of the workers
  42. * is called. This is done for optimal performance: if the farm is initialized,
  43. * but no call is made to it, child Node processes will be consuming the least
  44. * possible amount of memory.
  45. *
  46. * If an invalid message is detected, the child will exit (by throwing) with a
  47. * non-zero exit code.
  48. */
  49. process.on('message', request => {
  50. switch (request[0]) {
  51. case _types.CHILD_MESSAGE_INITIALIZE:
  52. const init = request;
  53. file = init[2];
  54. setupArgs = request[3];
  55. break;
  56. case _types.CHILD_MESSAGE_CALL:
  57. const call = request;
  58. execMethod(call[2], call[3]);
  59. break;
  60. case _types.CHILD_MESSAGE_END:
  61. end();
  62. break;
  63. default:
  64. throw new TypeError(
  65. 'Unexpected request from parent process: ' + request[0]
  66. );
  67. }
  68. });
  69. function reportSuccess(result) {
  70. if (!process || !process.send) {
  71. throw new Error('Child can only be used on a forked process');
  72. }
  73. process.send([_types.PARENT_MESSAGE_OK, result]);
  74. }
  75. function reportClientError(error) {
  76. return reportError(error, _types.PARENT_MESSAGE_CLIENT_ERROR);
  77. }
  78. function reportInitializeError(error) {
  79. return reportError(error, _types.PARENT_MESSAGE_SETUP_ERROR);
  80. }
  81. function reportError(error, type) {
  82. if (!process || !process.send) {
  83. throw new Error('Child can only be used on a forked process');
  84. }
  85. if (error == null) {
  86. error = new Error('"null" or "undefined" thrown');
  87. }
  88. process.send([
  89. type,
  90. error.constructor && error.constructor.name,
  91. error.message,
  92. error.stack,
  93. typeof error === 'object' ? _objectSpread({}, error) : error
  94. ]);
  95. }
  96. function end() {
  97. const main = require(file);
  98. if (!main.teardown) {
  99. exitProcess();
  100. return;
  101. }
  102. execFunction(main.teardown, main, [], exitProcess, exitProcess);
  103. }
  104. function exitProcess() {
  105. process.exit(0);
  106. }
  107. function execMethod(method, args) {
  108. const main = require(file);
  109. let fn;
  110. if (method === 'default') {
  111. fn = main.__esModule ? main['default'] : main;
  112. } else {
  113. fn = main[method];
  114. }
  115. function execHelper() {
  116. execFunction(fn, main, args, reportSuccess, reportClientError);
  117. }
  118. if (initialized || !main.setup) {
  119. execHelper();
  120. return;
  121. }
  122. initialized = true;
  123. execFunction(main.setup, main, setupArgs, execHelper, reportInitializeError);
  124. }
  125. function execFunction(fn, ctx, args, onResult, onError) {
  126. let result;
  127. try {
  128. result = fn.apply(ctx, args);
  129. } catch (err) {
  130. onError(err);
  131. return;
  132. }
  133. if (result && typeof result.then === 'function') {
  134. result.then(onResult, onError);
  135. } else {
  136. onResult(result);
  137. }
  138. }