index.js 6.3 KB

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