Skip to content

Exit state.event cleanly on Ctrl-c - #70688

Open
va000612 wants to merge 1 commit into
saltstack:3008.xfrom
va000612:fix/59618-fix-hang-states-exit-cleanly
Open

va000612 wants to merge 1 commit into
saltstack:3008.xfrom
va000612:fix/59618-fix-hang-states-exit-cleanly

Conversation

@va000612

@va000612 va000612 commented Nov 5, 2026 •

Copy link
Copy Markdown

What does this PR do?

salt-run state.event (and salt-call state.event) printed a traceback and reported the runner as failed when stopped with Ctrl+C.

salt-run installs a SIGINT handler (salt/scripts.py::_handle_signals) that calls sys.exit(). That SystemExit is raised while state.event is blocked inside sevent.get_event(), in the tornado/asyncio selector poll. Nothing in the loop caught it, so it propagated up to salt.client.mixins.low, which reported Exception occurred in runner state.event: Traceback ... SystemExit: 0 with retcode: 1.

This wraps the loop in try/except (KeyboardInterrupt, SystemExit) so the command stops quietly. The event bus is still closed by the surrounding with get_event(...) block.

What issues does this PR fix or reference?

Fixes #59618

Previous Behavior

Pressing Ctrl+C during salt-run state.event pretty=True printed Exiting gracefully on Ctrl-c followed by a traceback ending in SystemExit: 0, and the runner returned success: False, retcode: 1.

New Behavior

Ctrl+C prints only Exiting gracefully on Ctrl-c and the command ends without a traceback. count=N and event printing are unchanged.

Merge requirements satisfied?

  • Docs: no docs change needed
  • Changelog: changelog/59618.fixed.md
  • Tests written/updated: test_event_exits_cleanly_on_interrupt (parametrized over KeyboardInterrupt and SystemExit)

Testing

Unit tests (repo .venv, Python 3.14):

.venv/bin/python -m pytest tests/pytests/unit/modules/state/test_state.py -k test_event -q -p no:cacheprovider
  • Without the fix: the KeyboardInterrupt case escapes state.event and aborts the pytest session.
  • With the fix: 3 passed (existing test_event plus both new cases).
    Before:
Screenshot 2026-11-05 at 11 58 47 AM After: Screenshot 2026-11-05 at 11 58 56 AM

Real master (master, Salt 3008.4, Python 3.11, minion connected):

timeout -s INT 6 salt-run -c /root/repro/master state.event pretty=True >out.txt 2>err.txt
grep -c "Exception occurred in runner" err.txt
Exception occurred in runner stderr
Before (stock 3008.4) 1 traceback ending in SystemExit: 0, retcode: 1
After (patched salt/modules/state.py) 0 only Exiting gracefully on Ctrl-c

(timeout exit code 124 is expected in both cases.)

Regression check on the same master:

salt-run -c /root/repro/master state.event 'test/*' count=1 &
salt-run -c /root/repro/master event.send test/tag '{"a": 1}'

The listener printed test/tag {"a": 1, "_stamp": ...} and exited on its own.

Note: lint-salt, lint-tests and check-changelog-entries pre-commit hooks were skipped locally because of local environment problems (unresolvable pinned requirement, no py3.15 changelog lock). Please rely on CI for those.

salt-run installs a SIGINT handler that raises SystemExit, which escaped
the state.event loop mid-poll and was reported by the runner as an
exception with a traceback. Catch KeyboardInterrupt/SystemExit around the
loop so the command stops quietly; the event bus is still closed by the
with block.

Fixes saltstack#59618

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch was successfully deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant