source: trip-planner-front/node_modules/jest-worker/build/workers/ChildProcessWorker.js@ e29cc2e

Last change on this file since e29cc2e was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 7.9 KB
Line 
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6exports.default = void 0;
7
8function _child_process() {
9 const data = require('child_process');
10
11 _child_process = function () {
12 return data;
13 };
14
15 return data;
16}
17
18function _stream() {
19 const data = require('stream');
20
21 _stream = function () {
22 return data;
23 };
24
25 return data;
26}
27
28function _mergeStream() {
29 const data = _interopRequireDefault(require('merge-stream'));
30
31 _mergeStream = function () {
32 return data;
33 };
34
35 return data;
36}
37
38function _supportsColor() {
39 const data = require('supports-color');
40
41 _supportsColor = function () {
42 return data;
43 };
44
45 return data;
46}
47
48var _types = require('../types');
49
50function _interopRequireDefault(obj) {
51 return obj && obj.__esModule ? obj : {default: obj};
52}
53
54function _defineProperty(obj, key, value) {
55 if (key in obj) {
56 Object.defineProperty(obj, key, {
57 value: value,
58 enumerable: true,
59 configurable: true,
60 writable: true
61 });
62 } else {
63 obj[key] = value;
64 }
65 return obj;
66}
67
68const SIGNAL_BASE_EXIT_CODE = 128;
69const SIGKILL_EXIT_CODE = SIGNAL_BASE_EXIT_CODE + 9;
70const SIGTERM_EXIT_CODE = SIGNAL_BASE_EXIT_CODE + 15; // How long to wait after SIGTERM before sending SIGKILL
71
72const SIGKILL_DELAY = 500;
73/**
74 * This class wraps the child process and provides a nice interface to
75 * communicate with. It takes care of:
76 *
77 * - Re-spawning the process if it dies.
78 * - Queues calls while the worker is busy.
79 * - Re-sends the requests if the worker blew up.
80 *
81 * The reason for queueing them here (since childProcess.send also has an
82 * internal queue) is because the worker could be doing asynchronous work, and
83 * this would lead to the child process to read its receiving buffer and start a
84 * second call. By queueing calls here, we don't send the next call to the
85 * children until we receive the result of the previous one.
86 *
87 * As soon as a request starts to be processed by a worker, its "processed"
88 * field is changed to "true", so that other workers which might encounter the
89 * same call skip it.
90 */
91
92class ChildProcessWorker {
93 constructor(options) {
94 _defineProperty(this, '_child', void 0);
95
96 _defineProperty(this, '_options', void 0);
97
98 _defineProperty(this, '_request', void 0);
99
100 _defineProperty(this, '_retries', void 0);
101
102 _defineProperty(this, '_onProcessEnd', void 0);
103
104 _defineProperty(this, '_onCustomMessage', void 0);
105
106 _defineProperty(this, '_fakeStream', void 0);
107
108 _defineProperty(this, '_stdout', void 0);
109
110 _defineProperty(this, '_stderr', void 0);
111
112 _defineProperty(this, '_exitPromise', void 0);
113
114 _defineProperty(this, '_resolveExitPromise', void 0);
115
116 this._options = options;
117 this._request = null;
118 this._fakeStream = null;
119 this._stdout = null;
120 this._stderr = null;
121 this._exitPromise = new Promise(resolve => {
122 this._resolveExitPromise = resolve;
123 });
124 this.initialize();
125 }
126
127 initialize() {
128 const forceColor = _supportsColor().stdout
129 ? {
130 FORCE_COLOR: '1'
131 }
132 : {};
133 const child = (0, _child_process().fork)(
134 require.resolve('./processChild'),
135 [],
136 {
137 cwd: process.cwd(),
138 env: {
139 ...process.env,
140 JEST_WORKER_ID: String(this._options.workerId + 1),
141 // 0-indexed workerId, 1-indexed JEST_WORKER_ID
142 ...forceColor
143 },
144 // Suppress --debug / --inspect flags while preserving others (like --harmony).
145 execArgv: process.execArgv.filter(v => !/^--(debug|inspect)/.test(v)),
146 silent: true,
147 ...this._options.forkOptions
148 }
149 );
150
151 if (child.stdout) {
152 if (!this._stdout) {
153 // We need to add a permanent stream to the merged stream to prevent it
154 // from ending when the subprocess stream ends
155 this._stdout = (0, _mergeStream().default)(this._getFakeStream());
156 }
157
158 this._stdout.add(child.stdout);
159 }
160
161 if (child.stderr) {
162 if (!this._stderr) {
163 // We need to add a permanent stream to the merged stream to prevent it
164 // from ending when the subprocess stream ends
165 this._stderr = (0, _mergeStream().default)(this._getFakeStream());
166 }
167
168 this._stderr.add(child.stderr);
169 }
170
171 child.on('message', this._onMessage.bind(this));
172 child.on('exit', this._onExit.bind(this));
173 child.send([
174 _types.CHILD_MESSAGE_INITIALIZE,
175 false,
176 this._options.workerPath,
177 this._options.setupArgs
178 ]);
179 this._child = child;
180 this._retries++; // If we exceeded the amount of retries, we will emulate an error reply
181 // coming from the child. This avoids code duplication related with cleaning
182 // the queue, and scheduling the next call.
183
184 if (this._retries > this._options.maxRetries) {
185 const error = new Error(
186 `Jest worker encountered ${this._retries} child process exceptions, exceeding retry limit`
187 );
188
189 this._onMessage([
190 _types.PARENT_MESSAGE_CLIENT_ERROR,
191 error.name,
192 error.message,
193 error.stack,
194 {
195 type: 'WorkerError'
196 }
197 ]);
198 }
199 }
200
201 _shutdown() {
202 // End the temporary streams so the merged streams end too
203 if (this._fakeStream) {
204 this._fakeStream.end();
205
206 this._fakeStream = null;
207 }
208
209 this._resolveExitPromise();
210 }
211
212 _onMessage(response) {
213 // TODO: Add appropriate type check
214 let error;
215
216 switch (response[0]) {
217 case _types.PARENT_MESSAGE_OK:
218 this._onProcessEnd(null, response[1]);
219
220 break;
221
222 case _types.PARENT_MESSAGE_CLIENT_ERROR:
223 error = response[4];
224
225 if (error != null && typeof error === 'object') {
226 const extra = error; // @ts-expect-error: no index
227
228 const NativeCtor = global[response[1]];
229 const Ctor = typeof NativeCtor === 'function' ? NativeCtor : Error;
230 error = new Ctor(response[2]);
231 error.type = response[1];
232 error.stack = response[3];
233
234 for (const key in extra) {
235 error[key] = extra[key];
236 }
237 }
238
239 this._onProcessEnd(error, null);
240
241 break;
242
243 case _types.PARENT_MESSAGE_SETUP_ERROR:
244 error = new Error('Error when calling setup: ' + response[2]);
245 error.type = response[1];
246 error.stack = response[3];
247
248 this._onProcessEnd(error, null);
249
250 break;
251
252 case _types.PARENT_MESSAGE_CUSTOM:
253 this._onCustomMessage(response[1]);
254
255 break;
256
257 default:
258 throw new TypeError('Unexpected response from worker: ' + response[0]);
259 }
260 }
261
262 _onExit(exitCode) {
263 if (
264 exitCode !== 0 &&
265 exitCode !== null &&
266 exitCode !== SIGTERM_EXIT_CODE &&
267 exitCode !== SIGKILL_EXIT_CODE
268 ) {
269 this.initialize();
270
271 if (this._request) {
272 this._child.send(this._request);
273 }
274 } else {
275 this._shutdown();
276 }
277 }
278
279 send(request, onProcessStart, onProcessEnd, onCustomMessage) {
280 onProcessStart(this);
281
282 this._onProcessEnd = (...args) => {
283 // Clean the request to avoid sending past requests to workers that fail
284 // while waiting for a new request (timers, unhandled rejections...)
285 this._request = null;
286 return onProcessEnd(...args);
287 };
288
289 this._onCustomMessage = (...arg) => onCustomMessage(...arg);
290
291 this._request = request;
292 this._retries = 0;
293
294 this._child.send(request, () => {});
295 }
296
297 waitForExit() {
298 return this._exitPromise;
299 }
300
301 forceExit() {
302 this._child.kill('SIGTERM');
303
304 const sigkillTimeout = setTimeout(
305 () => this._child.kill('SIGKILL'),
306 SIGKILL_DELAY
307 );
308
309 this._exitPromise.then(() => clearTimeout(sigkillTimeout));
310 }
311
312 getWorkerId() {
313 return this._options.workerId;
314 }
315
316 getStdout() {
317 return this._stdout;
318 }
319
320 getStderr() {
321 return this._stderr;
322 }
323
324 _getFakeStream() {
325 if (!this._fakeStream) {
326 this._fakeStream = new (_stream().PassThrough)();
327 }
328
329 return this._fakeStream;
330 }
331}
332
333exports.default = ChildProcessWorker;
Note: See TracBrowser for help on using the repository browser.