UNPKG

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