Skip to content

Shutdown output races: "Goodbye" can print after the shell prompt returns on Ctrl+C #62

@melvincarvalho

Description

@melvincarvalho

Summary

When you stop the server with Ctrl+C, the shutdown messages print out of order — the parent's ✓ Server stopped / Goodbye! 👋 farewell can land after the shell prompt has already returned, and there's a duplicate "shutting down" line.

Root cause

Two processes share one terminal and both receive the Ctrl+C SIGINT:

  • Parent — the jspod CLI (index.js), the process the shell waits on.
  • Child — the real Solid server jss, spawned at lib/start.js:263 with stdio: 'inherit' and no detached flag, so it sits in the same foreground process group as the parent.

A terminal Ctrl+C delivers SIGINT to the whole process group, so both handlers run at once and race on the same TTY:

  • child (node_modules/javascript-solid-server/bin/jss.js:285): prints Shutting down...server.close() → exits.
  • parent (index.js:523): prints ⚠ Shutting down gracefully...await handle.stop() → prints ✓ Server stopped / Goodbye! 👋 → exits.

Result: a duplicated "shutting down" line, plus the farewell interleaving with the returning prompt.

Proposed fix (minimal, no orphan risk)

Keep both processes in the same group (so closing the terminal still tears the server down via SIGHUP — important for a dev server) and stop the parent from racing. The child already prints Shutting down... and exits on its own SIGINT, so the parent just needs to drop its redundant line; await handle.stop() already waits for the child to fully exit before the farewell prints.

process.on('SIGINT', async () => {
  await handle.stop();                       // waits for child to fully exit
  console.log(chalk.green('\n✓  Server stopped'));
  console.log(chalk.dim('Goodbye! 👋\n'));
  process.exit(0);
});

Expected output on Ctrl+C:

  Shutting down...      <- child
✓  Server stopped       <- parent, after child is gone
Goodbye! 👋
$                       <- prompt, last

Rejected alternative

Spawning the child detached: true also fixes the ordering, but the child then survives terminal close / parent crash — an orphaned server holding the port. Not worth it for a dev server.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions