Skip to content

fix[client]: Exit WebXR when failed to connect or streaming error#342

Merged
yanziz-nvidia merged 1 commit intomainfrom
yanziz/exit-when-fail
Apr 2, 2026
Merged

fix[client]: Exit WebXR when failed to connect or streaming error#342
yanziz-nvidia merged 1 commit intomainfrom
yanziz/exit-when-fail

Conversation

@yanziz-nvidia
Copy link
Copy Markdown
Contributor

@yanziz-nvidia yanziz-nvidia commented Apr 1, 2026

Summary by CodeRabbit

  • New Features

    • Immersive XR exit events now trigger the same cleanup and UI teardown as the manual disconnect action, ensuring teleop timers and state reset.
  • Bug Fixes

    • More robust error handling and resource cleanup for XR session failures (connection, stream, proxy, and reference-space issues), improving reliability of session termination and UI state.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 2026

📝 Walkthrough

Walkthrough

Added an optional onExitImmersiveXR prop to CloudXRComponent and invoked it across multiple CloudXR failure/termination paths; App now passes its handleDisconnect to that prop so immersive XR exits trigger the same teardown logic.

Changes

Cohort / File(s) Summary
CloudXRComponent Callback Handler
deps/cloudxr/webxr_client/helpers/react/CloudXRComponent.tsx
Added optional onExitImmersiveXR?: () => void to CloudXRComponentProps, stored in a ref, and invoked on proxy config failure, stream stop with error, session creation failure, connect failure (with best-effort disconnect and session cleanup), and when XR reference space is unavailable.
App Integration
deps/cloudxr/webxr_client/src/App.tsx
Passed existing handleDisconnect as onExitImmersiveXR to CloudXRComponent so immersive XR exit paths trigger the same disconnect/teardown sequence (timers, teleop state, session end).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped into props and found a door,
When XR stumbles, I call once more.
Cleanup scurries, timers cease to race,
Disconnects finish with gentle grace. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding exit handling for WebXR when connection fails or streaming errors occur, which matches the implementation across both modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yanziz/exit-when-fail

Comment @coderabbitai help to get the list of available commands and usage tips.

@yanziz-nvidia yanziz-nvidia requested review from blongs-nv and nvddr April 1, 2026 21:59
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
deps/cloudxr/webxr_client/src/App.tsx (1)

596-617: 🧹 Nitpick | 🔵 Trivial

Consider guarding against redundant session.end() calls.

If handleDisconnect is invoked multiple times in quick succession (e.g., from rapidly-firing error callbacks), calling end() on an already-ending session will reject with an InvalidStateError, displaying a potentially confusing message to the user.

A simple guard could prevent this:

🛡️ Optional: Add guard to prevent redundant session.end() calls
+  const isDisconnectingRef = useRef(false);

   const handleDisconnect = () => {
     console.log('Disconnect pressed');

     // Cleanup countdown state on disconnect
     if (countdownTimerRef.current !== null) {
       clearInterval(countdownTimerRef.current);
       countdownTimerRef.current = null;
     }
     setIsCountingDown(false);
     setCountdownRemaining(0);
     setIsTeleopRunning(false);

     const xrState = store.getState();
     const session = xrState.session;
-    if (session) {
+    if (session && !isDisconnectingRef.current) {
+      isDisconnectingRef.current = true;
       session.end().catch((err: unknown) => {
         setErrorMessage(
           `Failed to end XR session: ${err instanceof Error ? err.message : String(err)}`
         );
+      }).finally(() => {
+        isDisconnectingRef.current = false;
       });
     }
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deps/cloudxr/webxr_client/src/App.tsx` around lines 596 - 617,
handleDisconnect currently calls session.end() without guarding against repeated
calls; add a guard (eg. a ref or boolean like sessionEndingRef or
isSessionEnding state) and check it before calling session.end(), set it true
immediately before calling end(), and in the promise handlers
(then/catch/finally) reset it (false) or clear the ref so subsequent disconnects
are no-ops; update references to the XR session from store.getState().session
and ensure the flag is used around that session.end() invocation in
handleDisconnect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@deps/cloudxr/webxr_client/src/App.tsx`:
- Around line 596-617: handleDisconnect currently calls session.end() without
guarding against repeated calls; add a guard (eg. a ref or boolean like
sessionEndingRef or isSessionEnding state) and check it before calling
session.end(), set it true immediately before calling end(), and in the promise
handlers (then/catch/finally) reset it (false) or clear the ref so subsequent
disconnects are no-ops; update references to the XR session from
store.getState().session and ensure the flag is used around that session.end()
invocation in handleDisconnect.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e0745617-bcbf-453c-a90c-e0713749e6ee

📥 Commits

Reviewing files that changed from the base of the PR and between 8a61d96 and 483e340.

📒 Files selected for processing (2)
  • deps/cloudxr/webxr_client/helpers/react/CloudXRComponent.tsx
  • deps/cloudxr/webxr_client/src/App.tsx

@yanziz-nvidia yanziz-nvidia force-pushed the yanziz/exit-when-fail branch from 483e340 to e63df28 Compare April 2, 2026 05:17
@yanziz-nvidia yanziz-nvidia enabled auto-merge (squash) April 2, 2026 05:17
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
deps/cloudxr/webxr_client/helpers/react/CloudXRComponent.tsx (1)

348-352: 🧹 Nitpick | 🔵 Trivial

Consider early-exit pattern for improved readability.

The if (referenceSpace) block (lines 184-352) is quite long. An early-exit pattern would reduce nesting and improve readability, consistent with the past review suggestion:

♻️ Optional refactor: early-exit pattern
-        if (referenceSpace) {
+        if (!referenceSpace) {
+          onStatusChange?.(false, 'Reference Space Unavailable');
+          onError?.('Could not obtain an XR reference space for CloudXR');
+          onExitImmersiveXRRef.current?.();
+          return;
+        }
+
           // Ensure that the session is not already created.
           if (cxrSessionRef.current) {
             console.error('CloudXR session already exists');
             return;
           }
           // ... rest of session setup at reduced indent level ...
-        } else {
-          onStatusChange?.(false, 'Reference Space Unavailable');
-          onError?.('Could not obtain an XR reference space for CloudXR');
-          onExitImmersiveXRRef.current?.();
-        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deps/cloudxr/webxr_client/helpers/react/CloudXRComponent.tsx` around lines
348 - 352, Invert the large if (referenceSpace) block to use an early-exit: at
the start of the handler where referenceSpace is checked in
CloudXRComponent.tsx, add a guard if (!referenceSpace) { onStatusChange?.(false,
'Reference Space Unavailable'); onError?.('Could not obtain an XR reference
space for CloudXR'); onExitImmersiveXRRef.current?.(); return; } and then remove
the corresponding else branch so the remaining logic runs unindented; this keeps
calls to onStatusChange, onError, and onExitImmersiveXRRef the same but
simplifies control flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@deps/cloudxr/webxr_client/helpers/react/CloudXRComponent.tsx`:
- Around line 348-352: Invert the large if (referenceSpace) block to use an
early-exit: at the start of the handler where referenceSpace is checked in
CloudXRComponent.tsx, add a guard if (!referenceSpace) { onStatusChange?.(false,
'Reference Space Unavailable'); onError?.('Could not obtain an XR reference
space for CloudXR'); onExitImmersiveXRRef.current?.(); return; } and then remove
the corresponding else branch so the remaining logic runs unindented; this keeps
calls to onStatusChange, onError, and onExitImmersiveXRRef the same but
simplifies control flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: df1d61c8-ec50-42c0-8cd5-779b37dff203

📥 Commits

Reviewing files that changed from the base of the PR and between 483e340 and e63df28.

📒 Files selected for processing (2)
  • deps/cloudxr/webxr_client/helpers/react/CloudXRComponent.tsx
  • deps/cloudxr/webxr_client/src/App.tsx

@yanziz-nvidia yanziz-nvidia merged commit dbeed21 into main Apr 2, 2026
35 checks passed
@yanziz-nvidia yanziz-nvidia deleted the yanziz/exit-when-fail branch April 2, 2026 05:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants