#!/bin/bash # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Shared launch utilities for example scripts. # # Goal: # Unify behavior and reduce duplication across vLLM, SGLang, and TensorRT-LLM # example launch scripts so they share one pattern for banners, process # management, and example curl output. # # Benefits: # - Single place to change banner format, example prompts, and wait/cleanup logic # - Consistent UX: same startup output and exit behavior across all backends # - Less per-script boilerplate (no manual PID tracking or custom cleanup traps) # - wait_any_exit propagates the first failing child's exit code and lets the # EXIT trap tear down the rest, so failures and Ctrl+C behave predictably # # Usage: # source "$(dirname "$(readlink -f "$0")")/../common/launch_utils.sh" # # or with SCRIPT_DIR already set: # source "$SCRIPT_DIR/../common/launch_utils.sh" # # Constants: # EXAMPLE_PROMPT Default example prompt for curl commands (LLM / embedding) # EXAMPLE_PROMPT_VISUAL Default example prompt for image / video generation # # Requires: bash 4.3+ (wait -n) # # Functions: # print_launch_banner Print startup banner with model info and example curl # print_curl_footer Print a custom curl example with standard framing (heredoc) # wait_any_exit Wait for any background process to exit, propagate its code if [[ "${BASH_VERSINFO[0]}" -lt 4 || ( "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -lt 3 ) ]]; then echo "launch_utils.sh requires bash 4.3+ (for wait -n), found ${BASH_VERSION}" >&2 exit 1 fi EXAMPLE_PROMPT="Who is the tennis GOAT: Federer, Djokovic, or Nadal?" EXAMPLE_PROMPT_VISUAL="A golden retriever riding a skateboard through a neon-lit city" # wait_any_exit # # Waits for ANY backgrounded process to exit and propagates its exit code. # Call this as the LAST line of every launch script, after backgrounding # all processes (including the one that would otherwise run in the foreground). # # Why this is better than tracking PIDs manually or running in the foreground: # Foreground pattern: if the frontend crashes, the script blocks on the # foreground worker and never notices until that worker also exits. # Manual PIDs: requires bookkeeping ($DYNAMO_PID, $PREFILL_PID, ...), # a custom cleanup() function, and `wait $PID` only watches one process. # wait -n watches ALL children and returns as soon as ANY child dies, so # failures are detected immediately regardless of which process it was. # # Signal handling: # SIGTERM/SIGINT are trapped to exit 0 (clean shutdown). Without this, # external cleanup (e.g. a test harness sending SIGTERM to the process # group) interrupts wait -n, which returns 143 (128+15). Combined with # set -e, that non-zero code looks like a test failure. Trapping TERM/INT # makes external teardown exit cleanly while still propagating real errors # (OOM, Python exceptions, etc.) from child processes. # # The EXIT trap (set at the top of each script) still fires when this function # calls exit, tearing down the remaining processes via kill 0. # # Usage: # python -m dynamo.frontend & # python -m dynamo.vllm --model "$MODEL" & # wait_any_exit wait_any_exit() { trap 'exit 0' TERM INT if ! jobs -p | grep -q .; then echo "wait_any_exit: no background processes found (script bug: did you forget '&'?)" >&2 exit 1 fi wait -n local _rc=$? echo "A background process exited with code $_rc" exit "$_rc" } # print_launch_banner [flags]