test: tolerate non-zero Triton exit on Jetson graceful shutdown - #8881
Conversation
yinggeh
left a comment
There was a problem hiding this comment.
What is the root cause of "on Jetson, Triton may exit non-zero during graceful shutdown after Python backend stub teardown even when tests passed"?
On Orin, pytest passes but wait $SERVER_PID returns non-zero after shutdown, and sometimes a Python backend shm file is left in /dev/shm. This PR handles both in the QA harness on Jetson. Fixed in e2c7891. |
I understand. But what's the root cause for this buggy behavior? Why it's hardware specific? |
Good point , we only traced the CI symptom so far, not the full backend root cause. On IGX-Orin, pytest passes but shutdown sometimes exits non-zero before Python stub teardown finishes, which can leave shm files behind; we haven't reproduced that on x86. This PR is the QA harness fix for TRI-1330; I can dig into the Python backend shutdown path as well if you'd prefer that before merge. |
Please do. The goal of fixing tests is not simply to work around the issue, but to identify the root cause and file an NVBUG with the appropriate team if necessary. |
Makes sense , I'll dig into the Python backend shutdown path on Orin to find the root cause and file an NVBUG if it's a backend issue. I'll update here once I have findings. |
Root cause: lifecycle pytest passed, but Triton’s 30s shutdown timeout was too short for 7 Python stubs on Orin. Server exited with error, Python backend left an shm file behind, and the test failed on cleanup. We increased shutdown timeouts for Jetson, added harness cleanup as a safety net, and have a python_backend fix for proper stub teardown/shm cleanup. Verified green on Orin (job 366443271). |
Great. Make sure you linked the python_backend PR in the description (following the template format). |
| sed -i "s/TYPE_FP32/TYPE_UINT32/g" config.pbtxt) | ||
|
|
||
| prev_num_pages=`get_shm_pages` | ||
| if [ "${TEST_JETSON}" == "1" ]; then |
There was a problem hiding this comment.
With snapshot_triton_python_shm and cleanup_triton_python_shm_since_snapshot, the test won't detect any stale shm after server exits, which could be a problem.
There was a problem hiding this comment.
you're right that cleanup in kill_server runs before the shm count check, so it can mask leaks. I'll move cleanup to after the assertion (or remove it from kill_server and rely on the exit-timeout fix + python_backend PR). Will also link the python_backend PR in the description.
There was a problem hiding this comment.
Fixed in 3bbc4e0: the shm page-count assertion runs before cleanup_triton_python_shm_since_snapshot, and kill_server no longer does preemptive cleanup. Orin re-run for that commit is still pending.
There was a problem hiding this comment.
Also if it helps the test we should make it universal to all platforms.
There was a problem hiding this comment.
I looked at ShmLeakDetector vs the shell helpers.
They’re not quite the same: the detector is skipped on Jetson, and it checks free memory inside existing pools during pytest. The shell snapshot/cleanup handles leftover region files after server exit, which is what get_shm_pages() in test.sh was already watching.
Given that overlap, I’ll re-run Orin without snapshot/cleanup and drop them if it stays green. If we still need them, I’ll remove the TEST_JETSON guard and make them universal.
|
|
||
| TRITON_PYTHON_SHM_SNAPSHOT="" | ||
|
|
||
| function snapshot_triton_python_shm () { |
There was a problem hiding this comment.
Check
server/qa/L0_backend_python/lifecycle/lifecycle_test.py
Lines 66 to 68 in c1b7cb7
and find out if the shm functions are redundant.
| wait $SERVER_PID | ||
| # On Jetson, Triton may exit non-zero during graceful shutdown after | ||
| # Python backend stub teardown even when tests passed. | ||
| if [ "${TEST_JETSON}" == "1" ]; then |
There was a problem hiding this comment.
Do you still need special handling for Jetson?
There was a problem hiding this comment.
Yeah, but just two things now , shm cleanup is already out.
Orin still needs the 120s timeout and wait || true here. Without them the lifecycle test fails even when pytest passes.
Orin is green with only those (2734eb5). I kept the Jetson guard so other platforms don't silently ignore a bad shutdown.
There was a problem hiding this comment.
Nit: Have a generic wait $SERVER_PID || true for all platforms is fine. Just like your PR https://github.com/triton-inference-server/server/pull/
There was a problem hiding this comment.
Done ,dropped the Jetson guard and made wait $SERVER_PID || true universal.
| # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| # SPDX-FileCopyrightText: Copyright (c) 2018-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
There was a problem hiding this comment.
I think you need to revert the copyright change. Please rebase with the main branch and run pre_commit again.
Similar happened to me in the logging PR.
#8858 (comment)
There was a problem hiding this comment.
Done ,reverted the SPDX header, rebased on main, pre-commit passes. PR is now a clean 2-file diff.
Extend the exit-timeout window and Python stub-teardown window on
Jetson (${SERVER_TIMEOUT}, currently 120s) for
L0_backend_python/lifecycle, and make kill_server in qa/common/util.sh
tolerate a non-zero wait exit on all platforms so "set -e" does not
abort a suite when the server exits non-zero after shutdown.
Root cause on IGX-Orin: pytest passes but the default 30s shutdown
window is too short to tear down all Python stubs, so the server exits
non-zero and can leave a shm file behind, causing "wait $SERVER_PID"
under "set -e" to abort the rest of the suite.
cdc4d7e to
6b19f0f
Compare
Greptile SummaryThis PR tolerates non-zero Triton exit codes during graceful shutdown on Jetson/IGX-Orin, where seven Python backend stubs can exceed the default 30 s exit timeout, causing
Confidence Score: 4/5Safe to merge for its intended Jetson fix; the global The Jetson-conditional SERVER_ARGS change is well-scoped and correct. The qa/common/util.sh — the unconditional Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[kill_server called] --> B{Windows?}
B -- Yes --> C[tasklist / taskkill]
B -- No --> D{MSYSTEM set?}
D -- Yes --> E[taskkill //F //IM tritonserver.exe]
D -- No --> F[kill SERVER_PID SIGTERM]
F --> G["wait SERVER_PID || true"]
G --> H{Exit code?}
H -- 0 clean shutdown --> I[kill_server returns 0]
H -- non-zero timeout or crash --> J["|| true swallows exit"]
J --> I
I --> K[Caller continues under set -e]
K --> L{Has shm-page check?}
L -- Yes --> M[Orphaned pages detected as RET=1]
L -- No --> N[Server crash silently hidden]
Reviews (1): Last reviewed commit: "test: fix L0_backend_python/lifecycle sh..." | Re-trigger Greptile |
| # Non-windows... | ||
| kill $SERVER_PID | ||
| wait $SERVER_PID | ||
| wait $SERVER_PID || true |
There was a problem hiding this comment.
Unconditional
|| true masks server exit codes on all platforms
The || true is applied to every non-Windows host, not just Jetson. When a server exits non-zero during kill_server due to a crash or timeout on a standard x86 CI runner, the error is silently swallowed and the calling script under set -e sees success. Only tests that also perform a shm-page count check have a secondary safety net; tests without that check now lose the last signal that the server process ended badly.
| wait $SERVER_PID || true | |
| if [ "${TEST_JETSON}" == "1" ]; then | |
| wait $SERVER_PID || true | |
| else | |
| wait $SERVER_PID | |
| fi |
| if [ "${TEST_JETSON}" == "1" ]; then | ||
| SERVER_ARGS="${SERVER_ARGS} --exit-timeout-secs=${SERVER_TIMEOUT} --backend-config=python,stub-timeout-seconds=${SERVER_TIMEOUT}" | ||
| fi |
There was a problem hiding this comment.
stub-timeout-seconds is unbounded by SERVER_TIMEOUT semantics
SERVER_TIMEOUT (default 120 s) is designed as a readiness-wait budget, not a stub-shutdown budget. On Jetson it now doubles as both. If a Jetson CI runner is heavily loaded and stub teardown takes longer than 120 s in total (the root cause was seven stubs exceeding Triton's total 30 s budget), the same condition could recur with a different threshold. Consider defining a separate STUB_TIMEOUT with a value chosen specifically for Jetson stub teardown (e.g. 300 s), or at minimum adding a comment documenting why SERVER_TIMEOUT is adequate here.
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!
What does the PR do?
Fix
L0_backend_python/lifecyclefailures on IGX-Orin when pytest already passed.Root cause
Exit timeout expired, exited non-zero, andwait $SERVER_PIDfailed the script underset -e.triton_python_backend_shm_region_*files in/dev/shm.Fix
--exit-timeout-secs=${SERVER_TIMEOUT}andstub-timeout-seconds=${SERVER_TIMEOUT}inqa/L0_backend_python/lifecycle/test.sh.wait $SERVER_PID || trueinkill_server(qa/common/util.sh).qa/common/util.sh, lifecycle test).Checklist
<type>: <description>Commit Type:
Related PRs:
Where should the reviewer start?
qa/L0_backend_python/lifecycle/test.shqa/common/util.shTest plan:
qa/L0_backend_python/lifecycle/test.shwithTEST_JETSON=1.c1c44b50(Lifecycle test PASSED, shm count unchanged).3bbc4e05(run shm check before cleanup) still needs Orin re-run.Caveats:
Related Issues: