UNPKG

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