Skip to content

test(dev): cover repeated SIGINT/SIGTERM cleanup idempotency - #265

Merged
dDevAhmed merged 1 commit into
DigiNodes:mainfrom
ummarig:test/sw-061-sw-062-signal-idempotency
Oct 18, 2026
Merged

dDevAhmed merged 1 commit into
DigiNodes:mainfrom
ummarig:test/sw-061-sw-062-signal-idempotency

Conversation

@ummarig

@ummarig ummarig commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Summary

The dev supervisor's cleanup idempotency guard had no coverage.

dev-orchestrator.test.ts emits each signal exactly once:

signals.emit(signal);
await running;
expect(child.killedSignals).toEqual([signal]);

So the shuttingDown guard inside stopChildren — the single line that makes
cleanup run at most once — was never exercised under repetition.

Why this matters more than it looks

Without the guard, a user hammering Ctrl-C, or a container runtime delivering
SIGTERM alongside its own shutdown signal, would call child.kill() repeatedly. On
a real process group that escalates SIGINT → SIGKILL, and an already-exited child
gets signalled again. The visible symptom is a non-deterministic exit code instead
of a clean shutdown — the kind of bug that only reproduces in CI under load.

A test double that actually re-enters

process.once removes the listener after the first signal, so emitting twice
against the real process would not re-enter the handler and would prove
nothing. RepeatingSignalSource keeps the listener registered across emit, so
the second signal genuinely re-enters stopChildren — which is the behaviour under
test.

Four cases, parameterised over both signals so #162 and #163 are covered symmetrically:

Case Property
three consecutive signals each child killed exactly once
SIGTERM, then SIGTERM, then SIGINT no escalation to a second signal
shutdown requested twice resolves, rather than rejecting as "exited unexpectedly"
signal repeats handlers still removed in finally

The escalation case is the sharpest: it asserts that an interleaved SIGINT after a
SIGTERM does not change what the children received, which is precisely the
guarantee the guard provides.

Issue references

Closes #161

Closes #162

Closes #163

Closes #164

What this PR actually changes

Implemented in full — #162 (SIGINT) and #163 (SIGTERM).

Not implemented here:

Both were verified against the code rather than assumed. This file adds only the
repetition cases, which neither existing test touches.

Not run

node_modules was not installed and the suite was not executed, per your
constraint. Worth one local run to confirm — the resolves case depends on the
children reporting exit after kill(), which the FakeChild double drives via
queueMicrotask.

dev-orchestrator.test.ts emits each signal exactly once, so the shuttingDown guard
that makes cleanup run at most once was never exercised under repetition. That
guard is the whole safety story for a supervisor: without it a user hammering
Ctrl-C would call child.kill() repeatedly, escalating SIGINT to SIGKILL and
turning a clean shutdown into a non-deterministic exit.

A RepeatingSignalSource keeps the listener registered across emits, so a second
signal genuinely re-enters the handler - which process.once would not. Asserts
each child is killed exactly once however many signals arrive, that a second
SIGTERM and an interleaved SIGINT do not escalate, that a requested shutdown
resolves rather than rejecting as 'exited unexpectedly', and that signal handlers
are removed even when the signal repeats (DigiNodes#162, DigiNodes#163).
@coderabbitai

coderabbitai Bot commented Oct 18, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 40dc156e-0ad4-44b2-8961-db7a6b1a4b96
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dDevAhmed
dDevAhmed merged commit e6de9d8 into DigiNodes:main Oct 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants