Skip to content

feat: integrate retry logic Phase 3 #18699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: feature/terminal-reconnection-phase2
Choose a base branch
from

Conversation

BrunoQuaresma
Copy link
Collaborator

@BrunoQuaresma BrunoQuaresma commented Jul 1, 2025

  • Integrate useRetry hook into TerminalPage component
  • Add automatic retry trigger on disconnection
  • Implement terminal content preservation during reconnection
  • Update WebSocket connection logic to support retry mechanism
  • Pass retry props to TerminalAlerts component for UI display
  • Maintain existing terminal event handlers for data and resize
  • Use exponential backoff with 1s initial delay, 30s max, 10 attempts

useRetry Hook Improvements

  • Simplified timer management: Removed unnecessary startTimeRef and used local variables
  • Consolidated reducer logic: Streamlined return statements for cleaner state transitions
  • Split complex useEffect: Separated monolithic effect into focused, single-responsibility effects
  • Improved readability: Removed redundant comments and simplified countdown logic
  • Maintained API compatibility: All existing functionality and tests preserved
  • Reduced complexity: Fewer refs to manage, cleaner code flow

Completes Phase 3 of terminal reconnection feature as outlined in: coder/internal#659

- Integrate useRetry hook into TerminalPage component
- Add automatic retry trigger on disconnection
- Implement terminal content preservation during reconnection
- Update WebSocket connection logic to support retry mechanism
- Pass retry props to TerminalAlerts component for UI display
- Maintain existing terminal event handlers for data and resize
- Use exponential backoff with 1s initial delay, 30s max, 10 attempts

Completes Phase 3 of terminal reconnection feature as outlined in:
coder/internal#659

Co-authored-by: BrunoQuaresma <[email protected]>
blink-so bot and others added 6 commits July 1, 2025 18:48
- Add WEBSOCKET_CLOSE_NORMAL constant (1000) for normal closure
- Replace magic number 1000 with descriptive constant name
- Improves code readability and maintainability

Co-authored-by: BrunoQuaresma <[email protected]>
…Retry

- Add enabled prop to useRetry hook interface
- Remove startRetrying and stopRetrying methods from hook return
- Update TerminalPage to use enabled prop based on connection status
- Simplify retry logic with declarative enabled state
- Update tests to use enabled prop instead of manual start/stop calls
- Fix WebSocket close magic number with named constant

This makes the retry behavior more React-like and easier to reason about.
The hook now automatically starts/stops retrying based on the enabled prop.

Co-authored-by: BrunoQuaresma <[email protected]>
The issue was that when a retry succeeded, the state was reset to initial
state (attemptCount: 0), which triggered the useEffect to start retrying
again, creating an infinite loop.

Fixed by adding a hasStartedRef to track whether we've already started
the initial retry, preventing the hook from restarting after success.

Also removed onRetryEvent from performRetry dependency array since it's
created with useEffectEvent and should be stable.

Fixes the timeout in the 'should reset state when retry succeeds' test.

Co-authored-by: BrunoQuaresma <[email protected]>
The onRetryEvent is created with useEffectEvent and is stable across renders,
so it doesn't need to be in the dependency array. Added a suppression comment
to explain this to the linter.

Co-authored-by: BrunoQuaresma <[email protected]>
… comment

Since onRetryEvent is created with useEffectEvent, it's stable across renders
and can be safely included in the dependency array without causing issues.
This is cleaner than using a linter suppression comment.

Co-authored-by: BrunoQuaresma <[email protected]>
- Remove unnecessary startTimeRef and simplify timer management
- Consolidate reducer return statements for cleaner code
- Split complex useEffect into separate focused effects
- Remove redundant comments and simplify countdown logic
- Maintain same API and behavior while improving readability

Co-authored-by: BrunoQuaresma <[email protected]>
@BrunoQuaresma BrunoQuaresma changed the title feat: implement terminal reconnection Phase 3 - integrate retry logic feat: integrate retry logic Phase 3 Jul 1, 2025
@BrunoQuaresma BrunoQuaresma requested review from code-asher and a team July 1, 2025 20:03
@BrunoQuaresma
Copy link
Collaborator Author

@code-asher I also would appreciate a QA on this.

Copy link
Contributor

blink-so bot commented Jul 1, 2025

🧪 QA Testing Guide: Terminal Reconnection Feature

This guide will help you test the new terminal reconnection functionality with automatic retry logic.

🎯 What to Test

The terminal should now automatically attempt to reconnect when the WebSocket connection is lost, with exponential backoff retry logic and preserved terminal content.

🔧 Test Setup

  1. Start a workspace with a running agent
  2. Open the terminal in the Coder web UI
  3. Run some commands to generate terminal content (e.g., ls, pwd, echo "test")

📋 Test Scenarios

✅ Scenario 1: Network Interruption Simulation

Steps:

  1. Open browser DevTools → Network tab
  2. In the terminal, run a long-running command: ping google.com or tail -f /var/log/syslog
  3. In DevTools, enable "Offline" mode or throttle to "Offline"
  4. Wait 5-10 seconds
  5. Disable offline mode

Expected Behavior:

  • Terminal shows disconnected state
  • Retry attempts begin automatically (check for retry indicators in UI)
  • Terminal reconnects and resumes showing output
  • Previous terminal content is preserved (you should still see earlier commands)
  • No terminal clearing occurs during reconnection

✅ Scenario 2: Workspace Agent Restart

Steps:

  1. SSH into your workspace or use another terminal
  2. Restart the Coder agent: sudo systemctl restart coder-agent (or equivalent)
  3. Observe the web terminal behavior

Expected Behavior:

  • Terminal detects disconnection
  • Automatic retry attempts start
  • Terminal reconnects once agent is back online
  • Terminal content remains intact

✅ Scenario 3: Manual Retry Testing

Steps:

  1. Simulate a disconnection (using DevTools offline mode)
  2. Look for manual retry button/option in the UI
  3. Click manual retry while automatic retries are in progress

Expected Behavior:

  • Manual retry should work immediately
  • Should cancel any scheduled automatic retry
  • Connection should be re-established

✅ Scenario 4: Retry Exhaustion

Steps:

  1. Stop the workspace or agent completely
  2. Wait for all retry attempts to be exhausted (should be 10 attempts)
  3. Observe final state

Expected Behavior:

  • Retries should follow exponential backoff (1s, 2s, 4s, 8s, 16s, 30s, 30s...)
  • After 10 failed attempts, retries should stop
  • UI should indicate connection failed
  • Terminal content should still be preserved

✅ Scenario 5: Successful Mid-Retry Reconnection

Steps:

  1. Simulate disconnection
  2. Let 2-3 retry attempts fail
  3. Restore connectivity before all retries are exhausted

Expected Behavior:

  • Connection should be re-established on next retry attempt
  • Retry counter should reset
  • Terminal should resume normal operation

🔍 What to Look For

✅ UI Indicators

  • Connection status indicators (connected/disconnected/retrying)
  • Retry attempt counter or progress
  • Time until next retry countdown
  • Manual retry button availability

✅ Terminal Behavior

  • Content preservation: Previous commands and output remain visible
  • No clearing: Terminal doesn't clear during reconnection
  • Input handling: Terminal input is disabled during disconnection
  • Resume functionality: Can type and execute commands after reconnection

✅ Retry Logic

  • Automatic start: Retries begin immediately on disconnection
  • Exponential backoff: Delays increase (1s → 2s → 4s → 8s → 16s → 30s max)
  • Attempt limit: Stops after 10 attempts
  • Manual override: Manual retry works and cancels automatic retries

🐛 Common Issues to Watch For

  • Terminal clearing: Content should NEVER be cleared during reconnection
  • Infinite retries: Should stop after 10 attempts
  • UI freezing: Interface should remain responsive during retries
  • Memory leaks: Check for timer cleanup (DevTools → Performance)
  • Double connections: Ensure old connections are properly closed

🌐 Browser Testing

Test across different browsers:

  • Chrome/Chromium
  • Firefox
  • Safari (if available)
  • Edge

📱 Network Conditions

Test with various network conditions:

  • Stable connection
  • Slow 3G simulation
  • Intermittent connectivity
  • Complete offline periods

🎉 Success Criteria

The feature is working correctly if:

  1. Terminal automatically reconnects after network issues
  2. All previous terminal content is preserved
  3. Retry logic follows exponential backoff pattern
  4. Manual retry option is available and functional
  5. UI provides clear feedback about connection status
  6. No memory leaks or performance issues
  7. Works consistently across different browsers

Questions or Issues? Please comment below with:

  • Browser and version
  • Steps to reproduce any problems
  • Screenshots/videos if helpful
  • Console errors (if any)

Happy testing! 🚀

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.

1 participant