Consolidate CloudXR runtime lifecycle management: one supervised-launcher surface for apps, examples, and rig
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 25/100
- Tipo de issue
- Refactorización
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- python
- Área
- infrastructure
Línea de trabajo
Comienza comparando src/python/isaacteleop/cloudxr/launcher.py y runtime.py con rig/launcher.py; después, sigue el sondeo de estado en cloudxr/main.py, teleop_ros2_node.py, teleop_session.py y examples/camera_viz/camera_viz.py. Se considerará terminado cuando los llamadores utilicen un único contrato de ciclo de vida y comprobación de estado, la propiedad de las señales y del teardown esté definida, y rig ya no redefina la configuración del runtime de CloudXR.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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.
- Lenguaje dominante
- Python
- Estrellas
- 403
- Forks
- 94
- Merge medio
- 2 d 17 min
- PR fusionados (30 d)
- 121
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de NVIDIA/IsaacCapture
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
NVIDIA/IsaacCapture#910 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
NVIDIA/IsaacCapture#891 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 25/100
NVIDIA/IsaacCapture#1217 ·
Los mantenedores suelen responder en 1 día
-
Release Notes Draft: 1.5Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 20/100
NVIDIA/IsaacCapture#1214 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 50/100
NVIDIA/IsaacCapture#1181 ·
Los mantenedores suelen responder en 1 día
Todos los issues de NVIDIA/IsaacCapture
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
lidofinance/diffyscan#239 ·
Los mantenedores suelen responder en 1 día
-
docs: the dev-setup table and AGENTS.md name the reviewed_by guard that CI's Changelog job runsAbiertoarea: tools documentation good first issue ready for a contributor
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
eyalgolan/statecraft-israel#873 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
GET rooms API returns 500 due to nonexistent Room.is_active attributePosiblemente ocupada @Mars-60 la tomó hoy. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día
-
Add cover art to song rowsAbiertoenhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 5 días
-
Harmony OPeNDAP SubSetter (HOSS) Geographic production rssmif16d 7 XYZ_PROV
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
nasa/harmony-autotester#341 ·