← Recipes

阅读中文版本

Handle SIGINT Cleanup in a CLI

Trap interrupt signals to remove temporary files and flush progress so Ctrl-C does not leave a broken state.

~25 minclinodejsreliability

Task

Install signal handlers that clean up temporary resources before exiting.

When to use this

Interrupting a long CLI run leaves partial temp files and a half-written output that confuses the next run.

Prerequisites

  • A CLI that writes temporary files
  • A way to register signal handlers
  • A cleanup routine

Steps

1. Register handlers that clean up then exit.

const tmp = makeTempDir();
let done = false;
function cleanup() {
  if (done) return; done = true;
  rmSync(tmp, { recursive: true, force: true });
  process.exit(130);
}
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

Expected output: Ctrl-C removes temporary resources and exits with the conventional code.

2. Verify no leftovers remain after an interrupt.

tool long-job &
sleep 1 && kill -INT %1
ls /tmp | grep tool-tmp || echo 'no leftovers'

Expected output: The temp directory is gone, proving cleanup ran on interrupt.

Troubleshooting

Problem

Cleanup runs twice

Solution

Guard cleanup with an idempotency flag so both SIGINT and SIGTERM are safe.

Problem

Exit code wrong

Solution

Exit with 130 for SIGINT so scripts can distinguish interruption.

Limitations

  • SIGKILL cannot be trapped.
  • Async cleanup in handlers is limited.
  • Requires careful exit code semantics.

What this recipe does

Install signal handlers that clean up temporary resources before exiting.

Interrupting a long CLI run leaves partial temp files and a half-written output that confuses the next run.

Prerequisites

  • A CLI that writes temporary files
  • A way to register signal handlers
  • A cleanup routine

Procedure

  1. Register handlers that clean up then exit.
const tmp = makeTempDir();
let done = false;
function cleanup() {
  if (done) return; done = true;
  rmSync(tmp, { recursive: true, force: true });
  process.exit(130);
}
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

Expected result: Ctrl-C removes temporary resources and exits with the conventional code.

  1. Verify no leftovers remain after an interrupt.
tool long-job &
sleep 1 && kill -INT %1
ls /tmp | grep tool-tmp || echo 'no leftovers'

Expected result: The temp directory is gone, proving cleanup ran on interrupt.

How to confirm it worked

Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows interrupting the CLI leaves no temporary files and returns the conventional exit code.

Troubleshooting

Cleanup runs twice — Guard cleanup with an idempotency flag so both SIGINT and SIGTERM are safe.

Exit code wrong — Exit with 130 for SIGINT so scripts can distinguish interruption.

Limitations

  • SIGKILL cannot be trapped.
  • Async cleanup in handlers is limited.
  • Requires careful exit code semantics.