Consolidate CloudXR runtime lifecycle management: one supervised-launcher surface for apps, examples, and rig
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 25/100
- Tipo di issue
- Refactoring
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Tranquilla
- Stack tecnologico
- python
- Ambito
- infrastructure
Direzione di ricerca
Inizia confrontando src/python/isaacteleop/cloudxr/launcher.py e runtime.py con rig/launcher.py, quindi segui il polling dello stato in cloudxr/main.py, teleop_ros2_node.py, teleop_session.py ed examples/camera_viz/camera_viz.py. Il lavoro è completato quando i chiamanti usano un unico contratto per il ciclo di vita e il controllo dello stato, la responsabilità per i segnali e il teardown è definita e rig non ridefinisce più le impostazioni del runtime CloudXR.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
While reviewing #887 I formed the impression that the viz stack was re-inventing CloudXR lifecycle management. Checking the code, the premise needs one correction: src/viz/ (the C++ libraries) contains no CloudXR lifecycle code at all, and examples/camera_viz/camera_viz.py already imports and uses CloudXRLauncher (camera_viz.py:32, :394, :442). What it re-invents is not the launcher — it is the supervision policy around the launcher: manual __enter__/__exit__, its own signal handlers, its own health-poll plumbing, its own teardown-ordering rules. So the smell is real, it just lives one layer up from where I first placed it.
Every app that wants a managed CloudXR runtime today has to hand-roll the same four things: start it, hold it open, notice when it dies, tear it down in the right order. CloudXRLauncher gives you the first and the last; the middle two are copy-pasted per app, and they have already drifted.
Evidence
1. Four independent implementations of "poll the launcher's health from the app's main loop."
src/python/isaacteleop/cloudxr/__main__.py:260-272—while not stop: launcher.health_check(); time.sleep(0.1)with its own SIGINT/SIGTERM flag.examples/teleop_ros2/python/teleop_ros2_node.py:216and:225— one check between session attempts, one per step, each with a comment explaining why the other one is insufficient.src/python/isaacteleop/teleop_session_manager/teleop_session.py:922-924—_check_plugin_health(), the same pattern for plugin contexts.- PR #887 —
VizRunner.wait(health_check=...), threading a callable through the runner so the render-thread join loop can poll it.
The protocol name has already diverged: CloudXRLauncher.health_check() vs. plugin contexts' check_health(). Two names for one concept is a good sign the protocol was never designed, only repeatedly rediscovered.
2. Signal-handler collision in camera_viz.
CloudXRLauncher.__init__ installs chaining SIGTERM/SIGINT handlers (launcher.py:210, _install_signal_handlers). camera_viz.py:446 enters the launcher, then camera_viz.py:482-483 unconditionally overwrites both signals with its own _on_signal. On teardown, _restore_signal_handlers (launcher.py:559-568) sees signal.getsignal(sig) is not ours, drops the saved entry and returns without restoring — so the launcher's "stop the runtime on SIGTERM" guarantee is silently gone, and the process now depends on the finally block plus the atexit hook. It happens to work. It works by accident, and nothing in either file tells you the two are fighting over the same global.
3. rig/launcher.py re-derives what isaacteleop.cloudxr already owns. rig imports nothing from cloudxr today:
rig/launcher.py |
already exists in cloudxr |
|---|---|
_cloudxr_run_dir() re-parses --cloudxr-install-dir / $CXR_INSTALL_DIR / ~/.cloudxr (:149-169) |
EnvConfig.openxr_run_dir() (env_config.py:88) |
hard-coded "cloudxr.env" (:174) |
EnvConfig.env_filepath() (env_config.py:98) |
_RUNTIME_STARTED_SENTINEL = "runtime_started" (:69) |
the same sentinel written and polled by runtime.py:208, :244 |
CLOUDXR_ENV_WAIT_TIMEOUT_SEC = 120 (:64) |
RUNTIME_STARTUP_TIMEOUT_SEC = 30 (runtime.py:24) |
stale-sentinel deletion before launch (:337-344) |
_cleanup_stale_runtime (launcher.py:571-608) |
find_runtime_footguns lint for missing --no-launch-cloudxr-runtime (rig/config.py:264) |
the flag CloudXRLauncher.add_launch_cloudxr_runtime_argument registers |
The last row is the telling one: rig has to lint for a launcher CLI flag by string-matching user commands, because it has no structural relationship with the launcher whose behavior it depends on.
4. Duplication inside cloudxr itself, already drifted. launcher.py:604 cleans ("runtime_started", "monado.pid", "cloudxr.pid"); runtime.py:310 cleans ("ipc_cloudxr", "runtime_started", "monado.pid", "cloudxr.pid"). The launcher handles ipc_cloudxr separately just above, so the divergence is currently intentional — but it is exactly the shape that goes wrong when a fifth sentinel file gets added to one list and not the other.
Proposal
One supervised-lifecycle surface that owns the whole thing — start, signal/atexit registration, health polling, ordered teardown — with two ways to drive it:
- In-process: an app hands over its main loop (or its stop event) and gets runtime-death propagated as an exception on the main thread, without re-implementing the poll.
camera_viz,teleop_ros2,cloudxr/__main__, and any future viz app all collapse onto this. Note thatcamera_vizdrives aVizSession, not aTeleopSession, so this has to live belowTeleopSessionrather than inside it. - Out-of-process:
rigkeeps its tmux-pane model, but drives the same surface — importingEnvConfig/runtimefor run-dir, env-file name, sentinel name, and timeouts instead of re-deriving all four, and ideally replacing the footgun string-lint with something the launcher itself exposes.
Concrete sub-tasks:
- Unify the health-check protocol on one name and one contract (
health_check()vs.check_health()), and give it a single polling implementation instead of four. - Define who owns SIGINT/SIGTERM when a launcher and an app both want them, and make the
camera_vizcase work by construction rather than by luck. - Make
rig/launcher.pyimport run-dir, env-file name, sentinel name, and the startup timeout fromisaacteleop.cloudxrinstead of redefining them. - Merge
rigandCloudXRLauncherinto one lifecycle story — this has been the intent for a while and simply has not been done yet. - De-duplicate the stale-file cleanup lists between
launcher.pyandruntime.py. - Document the ordered-teardown rule that
camera_viz.py:436-440currently encodes as a comment (don't stop the runtime while a worker thread is insidesession.render()), so every app doesn't have to rediscover it.
Relationship to existing issues
- #701 (embed
CloudXRLauncherlifecycle insideTeleopSession) is a subset: it removes the nestedwithforTeleopSessioncallers. It does not covercamera_viz/viz apps (noTeleopSession), the health-check protocol, orrig. Whatever lands here should make #701 a thin wrapper rather than a parallel implementation. - #696 (update all examples to use
CloudXRLauncher) is about adoption; this issue is about what they adopt. - #887 is the motivating symptom, not the problem — it is a correct fix for a real bug, and the fact that fixing it required inventing a fifth health-poll site is the point.
- Lingua principale
- Python
- Stelle
- 403
- Fork
- 94
- Merge medio
- 2g 17m
- PR unite (30g)
- 121
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di NVIDIA/IsaacCapture
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
NVIDIA/IsaacCapture#910 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
NVIDIA/IsaacCapture#891 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
NVIDIA/IsaacCapture#1217 ·
I maintainer di solito rispondono entro 1 giorno
-
Release Notes Draft: 1.5Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 20/100
NVIDIA/IsaacCapture#1214 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 50/100
NVIDIA/IsaacCapture#1181 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di NVIDIA/IsaacCapture
Issue simili
-
area:core-platform effort:S priority:P3 status:in-review type:test
Difficoltà 2/5 Meno di un'ora Idoneità per principianti 80/100
randomparity/kdive#3246 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Requantification library converts m/z to mass with the hydrogen-atom mass instead of the proton massApertabug
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
nf-core/metaboigniter#130 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
common-workflow-language/cwl-utils#477 ·
I maintainer di solito rispondono entro 1 giorno
-
Add dependabotApertafeat
Difficoltà 2/5 Meno di un'ora Idoneità per principianti 72/100
open-nudge/opentemplate#204 ·
I maintainer di solito rispondono entro 1 giorno
-
github-stale-ci-pr-closer: KV state is double-wrapped, never persists, and hits the depth-32 limitForse già presa @VascoSch92 l’ha presa oggi. Apertapriority:medium ready-for-dev
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
OpenHands/extensions#781 ·
I maintainer di solito rispondono entro 1 giorno