Skip to content

Commit

Permalink
Prevent dev runtime from crashing upon HMR error
Browse files Browse the repository at this point in the history
Prevent development runtime from crashing miserably in an event of subsequent `ready` event received from the `ChildServer`. Also, force kill the underlying `ChildServer` process when terminating gracefully to make sure it does not spam to `stdout` after the dev process's terminated (often a case when the termination signal received, while the `ChildServer`'s still starting up in the background).
  • Loading branch information
shYkiSto authored and fusionjs-sync-bot[bot] committed Aug 31, 2022
1 parent fdd282a commit f20c2cb
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 31 deletions.
16 changes: 12 additions & 4 deletions fusion-cli/build/child-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

const child_process = require('child_process');
const ChildServerError = require('./child-server-error.js');
const {renderTerminalError} = require('./server-error.js');

/*::
type ChildServerOptions = {
Expand All @@ -34,7 +35,12 @@ class ChildServer {
}

onReady() {
throw new Error('Did not expect to receive another ready event from child');
const err = new Error(
'Did not expect to receive another ready event from child'
);
console.error(renderTerminalError(err));

this.onError(err);
}

onError(err /*: Error */) {
Expand Down Expand Up @@ -90,6 +96,8 @@ class ChildServer {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
});
this.proc.on('error', (err) => {
console.error(renderTerminalError(err));

handleChildError(err);
});
this.proc.on('exit', (code, signal) => {
Expand All @@ -101,8 +109,8 @@ class ChildServer {
.filter(Boolean)
.join('; ')}`
);
console.error(renderTerminalError(err));

console.error(err);
handleChildError(err);
});
this.proc.on('message', async (message) => {
Expand Down Expand Up @@ -150,7 +158,7 @@ class ChildServer {
}

_stopPromise = null;
stop() {
stop(isForced /*: boolean */ = false) {
if (this._stopPromise) {
return this._stopPromise;
}
Expand All @@ -164,7 +172,7 @@ class ChildServer {
this._startPromise = null;

this.proc.removeAllListeners();
if (this.options.debug) {
if (this.options.debug || isForced) {
this.proc.on('error', reject);
this.proc.on('exit', resolve);
this.proc.kill('SIGKILL');
Expand Down
6 changes: 3 additions & 3 deletions fusion-cli/build/dev-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,15 @@ module.exports.DevelopmentRuntime = function (
lifecycle.stop();
};

async function killProc() {
async function killProc(isForced) {
if (state.proxy) {
state.proxy.close();
state.proxy = null;
}

if (state.childServer) {
try {
await state.childServer.stop();
await state.childServer.stop(isForced);
} catch (err) {} // eslint-disable-line

state.childServer = null;
Expand Down Expand Up @@ -360,7 +360,7 @@ module.exports.DevelopmentRuntime = function (
state.server = null; // ensure we can call .run() again after stopping
}

await killProc();
await killProc(true);
};

return this;
Expand Down
49 changes: 25 additions & 24 deletions fusion-cli/commands/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,31 +144,32 @@ exports.run = async function (
const EXIT_SIGNALS = ['SIGINT', 'SIGTERM'];
let forceExit = false;
EXIT_SIGNALS.forEach((signal) => {
process.on(signal, function onSignalExit() {
function exit(exitCode = 0) {
EXIT_SIGNALS.forEach((signal) => process.off(signal, onSignalExit));
process.exit(exitCode);
}

if (forceExit || TERMINATION_GRACE_PERIOD === 0) {
return exit(1);
}
// User may force exit by sending termination signal a second time
forceExit = true;

console.log(
'\nGracefully shutting down... To force exit the process, press ^C again\n'
);

// Force exit should compiler take long time to close
if (Number.isFinite(TERMINATION_GRACE_PERIOD)) {
setTimeout(function () {
exit(1);
}, TERMINATION_GRACE_PERIOD);
}
stop(exit);
});
process.on(signal, onSignalExit);
});
function onSignalExit() {
function exit(exitCode = 0) {
EXIT_SIGNALS.forEach((signal) => process.off(signal, onSignalExit));
process.exit(exitCode);
}

if (forceExit || TERMINATION_GRACE_PERIOD === 0) {
return exit(1);
}
// User may force exit by sending termination signal a second time
forceExit = true;

console.log(
'\nGracefully shutting down... To force exit the process, press ^C again\n'
);

// Force exit should compiler take long time to close
if (Number.isFinite(TERMINATION_GRACE_PERIOD)) {
setTimeout(function () {
exit(1);
}, TERMINATION_GRACE_PERIOD);
}
stop(exit);
}

return {
compiler,
Expand Down

0 comments on commit f20c2cb

Please sign in to comment.