From 86d51a8ad26a8cbbc4631f343a5428c87b9cc571 Mon Sep 17 00:00:00 2001 From: Melvin Carvalho Date: Mon, 25 May 2026 20:45:23 +0200 Subject: [PATCH] fix(shutdown): stop Ctrl+C output racing the shell prompt (#62) The JSS child shares the CLI's process group, so a terminal Ctrl+C delivers SIGINT to both. The child already prints "Shutting down..." and exits on its own; the CLI was also printing "Shutting down gracefully..." and then printing the farewell on a fixed 1s timer, which raced the returning shell prompt. Drop the parent's redundant line and wait for the child's real exit before the farewell, so output stays ordered. Same process group, so closing the terminal still tears the server down (no detached orphan). Closes #62 --- index.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index a3408e5..cccc03f 100755 --- a/index.js +++ b/index.js @@ -924,15 +924,22 @@ jss.on('exit', (code) => { } }); -// Graceful shutdown +// Graceful shutdown. The JSS child shares our process group, so a terminal +// Ctrl+C delivers SIGINT to it too — it prints its own "Shutting down..." +// and exits. Don't duplicate that line; wait for the child's actual exit +// before the farewell, so the output stays ordered ahead of the returning +// shell prompt instead of racing a fixed timeout against it. process.on('SIGINT', () => { - console.log('\n' + chalk.yellow('⚠ Shutting down gracefully...')); - jss.kill('SIGTERM'); - setTimeout(() => { - console.log(chalk.green('āœ“ Server stopped')); - console.log(chalk.dim('\nGoodbye! šŸ‘‹\n')); + const farewell = () => { + console.log(chalk.green('\nāœ“ Server stopped')); + console.log(chalk.dim('Goodbye! šŸ‘‹\n')); process.exit(0); - }, 1000); + }; + if (jss.exitCode !== null || jss.signalCode !== null) return farewell(); + jss.once('exit', farewell); + jss.kill('SIGTERM'); + // Safety net: don't hang if the child ignores SIGTERM. + setTimeout(() => { try { jss.kill('SIGKILL'); } catch {} }, 5000); }); process.on('SIGTERM', () => {