Skip to content

Commit c10349b

Browse files
committed
fix: Improve useRetry hook logic
- Fix startRetrying to immediately perform first retry - Adjust retry scheduling conditions - Fix delay calculation for exponential backoff Still debugging test failures
1 parent c115f13 commit c10349b

File tree

1 file changed

+52
-36
lines changed

1 file changed

+52
-36
lines changed

site/src/hooks/useRetry.ts

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
6363
const [isRetrying, setIsRetrying] = useState(false);
6464
const [currentDelay, setCurrentDelay] = useState<number | null>(null);
6565
const [attemptCount, setAttemptCount] = useState(0);
66-
const [timeUntilNextRetry, setTimeUntilNextRetry] = useState<number | null>(null);
66+
const [timeUntilNextRetry, setTimeUntilNextRetry] = useState<number | null>(
67+
null,
68+
);
6769
const [isManualRetry, setIsManualRetry] = useState(false);
6870

6971
const timeoutRef = useRef<number | null>(null);
@@ -84,10 +86,13 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
8486
startTimeRef.current = null;
8587
}, []);
8688

87-
const calculateDelay = useCallback((attempt: number): number => {
88-
const delay = initialDelay * Math.pow(multiplier, attempt);
89-
return Math.min(delay, maxDelay);
90-
}, [initialDelay, multiplier, maxDelay]);
89+
const calculateDelay = useCallback(
90+
(attempt: number): number => {
91+
const delay = initialDelay * multiplier ** attempt;
92+
return Math.min(delay, maxDelay);
93+
},
94+
[initialDelay, multiplier, maxDelay],
95+
);
9196

9297
const performRetry = useCallback(async () => {
9398
setIsRetrying(true);
@@ -103,47 +108,56 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
103108
setIsManualRetry(false);
104109
} catch (error) {
105110
// If retry fails, schedule next attempt (if not manual and under max attempts)
106-
setAttemptCount(prev => prev + 1);
111+
setAttemptCount((prev) => prev + 1);
107112
setIsRetrying(false);
108113
setIsManualRetry(false);
109114
}
110115
}, [onRetryEvent, clearTimers]);
111116

112-
const scheduleNextRetry = useCallback((attempt: number) => {
113-
if (attempt >= maxAttempts) {
114-
return;
115-
}
117+
const scheduleNextRetry = useCallback(
118+
(attempt: number) => {
119+
if (attempt >= maxAttempts) {
120+
return;
121+
}
116122

117-
const delay = calculateDelay(attempt);
118-
setCurrentDelay(delay);
119-
setTimeUntilNextRetry(delay);
120-
startTimeRef.current = Date.now();
121-
122-
// Start countdown timer
123-
countdownRef.current = setInterval(() => {
124-
if (startTimeRef.current) {
125-
const elapsed = Date.now() - startTimeRef.current;
126-
const remaining = Math.max(0, delay - elapsed);
127-
setTimeUntilNextRetry(remaining);
128-
129-
if (remaining <= 0) {
130-
if (countdownRef.current) {
131-
clearInterval(countdownRef.current);
132-
countdownRef.current = null;
123+
// Calculate delay based on attempt - 2 (so second attempt gets initialDelay)
124+
const delay = calculateDelay(Math.max(0, attempt - 2));
125+
setCurrentDelay(delay);
126+
setTimeUntilNextRetry(delay);
127+
startTimeRef.current = Date.now();
128+
129+
// Start countdown timer
130+
countdownRef.current = setInterval(() => {
131+
if (startTimeRef.current) {
132+
const elapsed = Date.now() - startTimeRef.current;
133+
const remaining = Math.max(0, delay - elapsed);
134+
setTimeUntilNextRetry(remaining);
135+
136+
if (remaining <= 0) {
137+
if (countdownRef.current) {
138+
clearInterval(countdownRef.current);
139+
countdownRef.current = null;
140+
}
133141
}
134142
}
135-
}
136-
}, 100); // Update every 100ms for smooth countdown
143+
}, 100); // Update every 100ms for smooth countdown
137144

138-
// Schedule the actual retry
139-
timeoutRef.current = setTimeout(() => {
140-
performRetry();
141-
}, delay);
142-
}, [calculateDelay, maxAttempts, performRetry]);
145+
// Schedule the actual retry
146+
timeoutRef.current = setTimeout(() => {
147+
performRetry();
148+
}, delay);
149+
},
150+
[calculateDelay, maxAttempts, performRetry],
151+
);
143152

144153
// Effect to schedule next retry after a failed attempt
145154
useEffect(() => {
146-
if (!isRetrying && !isManualRetry && attemptCount > 0 && attemptCount < maxAttempts) {
155+
if (
156+
!isRetrying &&
157+
!isManualRetry &&
158+
attemptCount > 1 &&
159+
attemptCount <= maxAttempts
160+
) {
147161
scheduleNextRetry(attemptCount);
148162
}
149163
}, [attemptCount, isRetrying, isManualRetry, maxAttempts, scheduleNextRetry]);
@@ -157,8 +171,10 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
157171
}, [clearTimers, performRetry]);
158172

159173
const startRetrying = useCallback(() => {
160-
setAttemptCount(1); // This will trigger the first retry attempt
161-
}, []);
174+
// Immediately perform the first retry attempt
175+
setAttemptCount(1);
176+
performRetry();
177+
}, [performRetry]);
162178

163179
const stopRetrying = useCallback(() => {
164180
clearTimers();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy