Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ Guidelines for modifications:
* Xu Li
* Yang Jin
* Yanzi Zhu
* Yichao Gan
* Yijie Guo
* Yize Wang
* Yohan Choi
Expand Down
5 changes: 5 additions & 0 deletions source/isaaclab/changelog.d/rx-02333-fix-sigterm-shutdown.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fixed
^^^^^

* Fixed :class:`~isaaclab.app.AppLauncher` leaving Python processes
running after receiving ``SIGTERM``.
7 changes: 6 additions & 1 deletion source/isaaclab/isaaclab/app/app_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def _atexit_close(app=self._app):

# Set up signal handlers for graceful shutdown
# -- during explicit `kill` commands
signal.signal(signal.SIGTERM, self._abort_signal_handle_callback)
signal.signal(signal.SIGTERM, self._terminate_signal_handle_callback)
# -- during aborts
signal.signal(signal.SIGABRT, self._abort_signal_handle_callback)
# -- during segfaults
Expand Down Expand Up @@ -1376,6 +1376,11 @@ def _interrupt_signal_handle_callback(self, signal, frame):
# raise the error for keyboard interrupt
raise KeyboardInterrupt

@staticmethod
def _terminate_signal_handle_callback(signum, _frame):
"""Terminate the process while preserving Python cleanup handlers."""
raise SystemExit(128 + signum)

def is_isaac_sim_version_5(self) -> bool:
if not hasattr(self, "_is_sim_ver_5"):
# 1) Try to read the VERSION file (for manual / binary installs)
Expand Down
18 changes: 18 additions & 0 deletions source/isaaclab/test/app/test_signal_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

import signal

import pytest

from isaaclab.app import AppLauncher


def test_sigterm_handler_terminates_process():
"""SIGTERM must terminate Python instead of resuming after the handler."""
with pytest.raises(SystemExit) as exc_info:
AppLauncher._terminate_signal_handle_callback(signal.SIGTERM, None)

assert exc_info.value.code == 128 + signal.SIGTERM
Comment on lines +13 to +18

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Test covers callback but not handler registration

The test exercises _terminate_signal_handle_callback directly, confirming the SystemExit(143) path. It does not assert that signal.getsignal(signal.SIGTERM) actually points to this method after AppLauncher initialises. If the registration line were accidentally reverted or guarded behind a condition, the test would still pass. A complementary integration-level assertion (e.g. checking signal.getsignal(signal.SIGTERM) after constructing an AppLauncher) would close this gap, though doing so requires the full Isaac Sim environment.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!