-
Notifications
You must be signed in to change notification settings - Fork 928
chore: add useWithRetry hook #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
base: main
Are you sure you want to change the base?
chore: add useWithRetry hook #18699
Conversation
- Update ConnectionStatus type: replace 'initializing' with 'connecting' - Create useRetry hook with exponential backoff logic - Add comprehensive tests for useRetry hook - Export useRetry from hooks index Implements: - Initial delay: 1 second - Max delay: 30 seconds - Backoff multiplier: 2 - Max retry attempts: 10 Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
- Fix startRetrying to immediately perform first retry - Adjust retry scheduling conditions - Fix delay calculation for exponential backoff Still debugging test failures
- Fix attemptCount to represent attempts started, not completed - Fix exponential backoff delay calculation - Fix retry scheduling conditions for proper max attempts handling - All 10 useRetry tests now pass - No regressions in existing test suite Implements correct behavior: - attemptCount increments when retry starts - Exponential backoff: 1s, 2s, 4s, 8s, 16s, 30s (capped) - Respects maxAttempts limit - Manual retry cancels automatic retries - State resets properly on success Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
- Add parentheses around arrow function parameter - Fix indentation Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
- Replace setTimeout/setInterval with window.setTimeout/window.setInterval - Replace clearTimeout/clearInterval with window.clearTimeout/window.clearInterval - Fixes TypeScript error: Type 'Timeout' is not assignable to type 'number' - Ensures proper browser environment timer types Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
Convert useRetry hook from multiple useState calls to a single useReducer for cleaner state management. This improves code clarity and makes state transitions more predictable. Changes: - Replace 5 useState calls with single useReducer - Add RetryState interface and RetryAction union type - Implement retryReducer function for all state transitions - Update all state access to use state object - Replace setState calls with dispatch calls throughout Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
- Create TerminalRetryConnection component with countdown display and retry button - Add comprehensive Storybook stories covering all retry states - Integrate component with TerminalAlerts for proper positioning - Use consistent TerminalAlert styling for seamless integration - Ensure proper resize handling through existing MutationObserver Implements Phase 2 of terminal reconnection feature as outlined in: coder/internal#659 Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
- Change 'import type { FC }' to 'import { type FC }' to match existing patterns - Verified with prettier that formatting is correct Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
…ectedAlert - Simplify TerminalRetryConnection to show only retry status and button - Keep existing DisconnectedAlert but add TerminalRetryConnection in actions - Use TailwindCSS classes instead of CSS-in-JS - Place retry component on the right side of the alert - Make retry messages smaller and more concise - Fix console.log usage in Storybook stories Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
- Remove RefreshSessionButton from DisconnectedAlert actions - Keep only TerminalRetryConnection component in the actions area - Simplify the actions layout by removing the wrapper div Co-authored-by: BrunoQuaresma <3165839+BrunoQuaresma@users.noreply.github.com>
- 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 <3165839+BrunoQuaresma@users.noreply.github.com>
- 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 <3165839+BrunoQuaresma@users.noreply.github.com>
…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 <3165839+BrunoQuaresma@users.noreply.github.com>
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 <3165839+BrunoQuaresma@users.noreply.github.com>
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 <3165839+BrunoQuaresma@users.noreply.github.com>
… 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 <3165839+BrunoQuaresma@users.noreply.github.com>
- 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 <3165839+BrunoQuaresma@users.noreply.github.com>
@code-asher I also would appreciate a QA on this. |
🧪 QA Testing Guide: Terminal Reconnection FeatureThis guide will help you test the new terminal reconnection functionality with automatic retry logic. 🎯 What to TestThe terminal should now automatically attempt to reconnect when the WebSocket connection is lost, with exponential backoff retry logic and preserved terminal content. 🔧 Test Setup
📋 Test Scenarios✅ Scenario 1: Network Interruption SimulationSteps:
Expected Behavior:
✅ Scenario 2: Workspace Agent RestartSteps:
Expected Behavior:
✅ Scenario 3: Manual Retry TestingSteps:
Expected Behavior:
✅ Scenario 4: Retry ExhaustionSteps:
Expected Behavior:
✅ Scenario 5: Successful Mid-Retry ReconnectionSteps:
Expected Behavior:
🔍 What to Look For✅ UI Indicators
✅ Terminal Behavior
✅ Retry Logic
🐛 Common Issues to Watch For
🌐 Browser TestingTest across different browsers:
📱 Network ConditionsTest with various network conditions:
🎉 Success Criteria✅ The feature is working correctly if:
Questions or Issues? Please comment below with:
Happy testing! 🚀 |
useWithRetry Hook Features
{ call, retryAt, isLoading }
for easy integrationConfiguration Options
maxAttempts
(default: 3)initialDelay
(default: 1000ms)maxDelay
(default: 8000ms)multiplier
(default: 2)Usage Example
This provides a cleaner, more focused approach to retry functionality that can be easily integrated into the TerminalPage component.