Skip to content

fix: Exit 130 or 143 when a signal interrupts a running task - #2759

Merged
milesj merged 4 commits into
moonrepo:masterfrom
devtechedge:fix-interrupt-exit-code
Oct 13, 2026
Merged

milesj merged 4 commits into
moonrepo:masterfrom
devtechedge:fix-interrupt-exit-code

Conversation

@devtechedge

Copy link
Copy Markdown
Contributor

Thanks for the clear report in #2758.

When moon run receives SIGINT or SIGTERM while a task is already running, moon stops the task and exits 0.

The summary also counts that task as skipped, so a wrapper such as timeout 600 moon run app:test && deploy treats the interrupt as success.

The in-flight job was finished as skipped even though its command had already run.

That job is now a failed run, and moon exits with 128 plus the signal number, 130 for SIGINT and 143 for SIGTERM.

A task that had not started is still skipped.

A SIGTERM now prints (terminated) rather than (interrupted), which is the status the pipeline already used when no task had started.

I checked this on Linux by sending SIGINT and SIGTERM to a running sleep task, and both the process status and the summary matched.

Fixes #2758

Comment thread crates/app/src/commands/exec.rs Outdated
// Set when the pipeline was stopped by a signal (130 / 143).
// Return it before the task-failure fallback, which would collapse
// an interrupt to 1.
if let Some(code) = self.session.exit_code.get() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just set line 307 below to this value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Miles, that's cleaner 👍

exit_code now starts from self.session.exit_code.get(), and the separate early return is gone.

The signal code still wins over a task's code, and the SIGINT and SIGTERM tests still pass with 130 and 143.

@devtechedge
devtechedge force-pushed the fix-interrupt-exit-code branch from f27f8d3 to 0292559 Compare October 11, 2026 05:58
// Capture and handle any signals. A task that was already running
// cancels the token before this point, so the status may already be
// set. Read the signal that was stored, instead of assuming interrupt.
if let Some(signal) = signal_slot.lock().ok().and_then(|slot| *slot) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devtechedge This branch is a bit confusing. Couldn't this just be done in the else branch? Or just merge the branches.

I don't think a slot is necessary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, the slot was more machinery than this needed 🙂

I dropped the shared slot and merged the signal handling into a single branch that awaits the monitor task whenever the token is cancelled.

The monitor is the only thing that cancels that token and it returns right after, so the await doesn't block and we always get the real signal, even when a running task already set the status.

Clippy is clean, and the SIGINT and SIGTERM tests still exit 130 and 143 with the task counted as failed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is much cleaner, thanks!

@devtechedge
devtechedge force-pushed the fix-interrupt-exit-code branch from 439079e to 9e03ff6 Compare October 12, 2026 00:45
@codspeed

codspeed Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 49.85%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

❌ 1 regressed benchmark
✅ 22 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ hash_files[1000] 9.3 ms 18.6 ms -49.85%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing devtechedge:fix-interrupt-exit-code (62737b7) with master (7ff97ad)

Open in CodSpeed

@devtechedge

Copy link
Copy Markdown
Contributor Author

@milesj I pushed a small test hardening, and the earlier failures were Node download timeouts unrelated to this change. Could you approve the workflows when you get a chance?

@milesj

milesj commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

Thanks!

@milesj
milesj merged commit 756b43e into moonrepo:master Oct 13, 2026
@devtechedge

Copy link
Copy Markdown
Contributor Author

Thanks for the reviews and the merge, Miles!

The suggestions made this a lot cleaner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

[bug] moon run exits 0 after SIGINT or SIGTERM interrupts a running task

2 participants