index.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. Object.defineProperty(exports, 'messageParent', {
  6. enumerable: true,
  7. get: function () {
  8. return _messageParent.default;
  9. }
  10. });
  11. exports.default = void 0;
  12. function _os() {
  13. const data = require('os');
  14. _os = function () {
  15. return data;
  16. };
  17. return data;
  18. }
  19. var _Farm = _interopRequireDefault(require('./Farm'));
  20. var _WorkerPool = _interopRequireDefault(require('./WorkerPool'));
  21. var _messageParent = _interopRequireDefault(require('./workers/messageParent'));
  22. function _interopRequireDefault(obj) {
  23. return obj && obj.__esModule ? obj : {default: obj};
  24. }
  25. function _defineProperty(obj, key, value) {
  26. if (key in obj) {
  27. Object.defineProperty(obj, key, {
  28. value: value,
  29. enumerable: true,
  30. configurable: true,
  31. writable: true
  32. });
  33. } else {
  34. obj[key] = value;
  35. }
  36. return obj;
  37. }
  38. function getExposedMethods(workerPath, options) {
  39. let exposedMethods = options.exposedMethods; // If no methods list is given, try getting it by auto-requiring the module.
  40. if (!exposedMethods) {
  41. const module = require(workerPath);
  42. exposedMethods = Object.keys(module).filter(
  43. // @ts-expect-error: no index
  44. name => typeof module[name] === 'function'
  45. );
  46. if (typeof module === 'function') {
  47. exposedMethods = [...exposedMethods, 'default'];
  48. }
  49. }
  50. return exposedMethods;
  51. }
  52. /**
  53. * The Jest farm (publicly called "Worker") is a class that allows you to queue
  54. * methods across multiple child processes, in order to parallelize work. This
  55. * is done by providing an absolute path to a module that will be loaded on each
  56. * of the child processes, and bridged to the main process.
  57. *
  58. * Bridged methods are specified by using the "exposedMethods" property of the
  59. * "options" object. This is an array of strings, where each of them corresponds
  60. * to the exported name in the loaded module.
  61. *
  62. * You can also control the amount of workers by using the "numWorkers" property
  63. * of the "options" object, and the settings passed to fork the process through
  64. * the "forkOptions" property. The amount of workers defaults to the amount of
  65. * CPUS minus one.
  66. *
  67. * Queueing calls can be done in two ways:
  68. * - Standard method: calls will be redirected to the first available worker,
  69. * so they will get executed as soon as they can.
  70. *
  71. * - Sticky method: if a "computeWorkerKey" method is provided within the
  72. * config, the resulting string of this method will be used as a key.
  73. * Every time this key is returned, it is guaranteed that your job will be
  74. * processed by the same worker. This is specially useful if your workers
  75. * are caching results.
  76. */
  77. class JestWorker {
  78. constructor(workerPath, options) {
  79. var _this$_options$enable,
  80. _this$_options$forkOp,
  81. _this$_options$maxRet,
  82. _this$_options$numWor,
  83. _this$_options$resour,
  84. _this$_options$setupA;
  85. _defineProperty(this, '_ending', void 0);
  86. _defineProperty(this, '_farm', void 0);
  87. _defineProperty(this, '_options', void 0);
  88. _defineProperty(this, '_workerPool', void 0);
  89. this._options = {...options};
  90. this._ending = false;
  91. const workerPoolOptions = {
  92. enableWorkerThreads:
  93. (_this$_options$enable = this._options.enableWorkerThreads) !== null &&
  94. _this$_options$enable !== void 0
  95. ? _this$_options$enable
  96. : false,
  97. forkOptions:
  98. (_this$_options$forkOp = this._options.forkOptions) !== null &&
  99. _this$_options$forkOp !== void 0
  100. ? _this$_options$forkOp
  101. : {},
  102. maxRetries:
  103. (_this$_options$maxRet = this._options.maxRetries) !== null &&
  104. _this$_options$maxRet !== void 0
  105. ? _this$_options$maxRet
  106. : 3,
  107. numWorkers:
  108. (_this$_options$numWor = this._options.numWorkers) !== null &&
  109. _this$_options$numWor !== void 0
  110. ? _this$_options$numWor
  111. : Math.max((0, _os().cpus)().length - 1, 1),
  112. resourceLimits:
  113. (_this$_options$resour = this._options.resourceLimits) !== null &&
  114. _this$_options$resour !== void 0
  115. ? _this$_options$resour
  116. : {},
  117. setupArgs:
  118. (_this$_options$setupA = this._options.setupArgs) !== null &&
  119. _this$_options$setupA !== void 0
  120. ? _this$_options$setupA
  121. : []
  122. };
  123. if (this._options.WorkerPool) {
  124. // @ts-expect-error: constructor target any?
  125. this._workerPool = new this._options.WorkerPool(
  126. workerPath,
  127. workerPoolOptions
  128. );
  129. } else {
  130. this._workerPool = new _WorkerPool.default(workerPath, workerPoolOptions);
  131. }
  132. this._farm = new _Farm.default(
  133. workerPoolOptions.numWorkers,
  134. this._workerPool.send.bind(this._workerPool),
  135. this._options.computeWorkerKey
  136. );
  137. this._bindExposedWorkerMethods(workerPath, this._options);
  138. }
  139. _bindExposedWorkerMethods(workerPath, options) {
  140. getExposedMethods(workerPath, options).forEach(name => {
  141. if (name.startsWith('_')) {
  142. return;
  143. }
  144. if (this.constructor.prototype.hasOwnProperty(name)) {
  145. throw new TypeError('Cannot define a method called ' + name);
  146. } // @ts-expect-error: dynamic extension of the class instance is expected.
  147. this[name] = this._callFunctionWithArgs.bind(this, name);
  148. });
  149. }
  150. _callFunctionWithArgs(method, ...args) {
  151. if (this._ending) {
  152. throw new Error('Farm is ended, no more calls can be done to it');
  153. }
  154. return this._farm.doWork(method, ...args);
  155. }
  156. getStderr() {
  157. return this._workerPool.getStderr();
  158. }
  159. getStdout() {
  160. return this._workerPool.getStdout();
  161. }
  162. async end() {
  163. if (this._ending) {
  164. throw new Error('Farm is ended, no more calls can be done to it');
  165. }
  166. this._ending = true;
  167. return this._workerPool.end();
  168. }
  169. }
  170. exports.default = JestWorker;