mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-26 13:04:49 -07:00
chore: do not retry the model request if the user has aborted the request (#11224)
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
isProQuotaExceededError,
|
||||
isGenericQuotaExceededError,
|
||||
} from './quotaErrorDetection.js';
|
||||
import { delay, createAbortError } from './delay.js';
|
||||
|
||||
const FETCH_FAILED_MESSAGE =
|
||||
'exception TypeError: fetch failed sending request';
|
||||
@@ -31,6 +32,7 @@ export interface RetryOptions {
|
||||
) => Promise<string | boolean | null>;
|
||||
authType?: string;
|
||||
retryFetchErrors?: boolean;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
const DEFAULT_RETRY_OPTIONS: RetryOptions = {
|
||||
@@ -75,15 +77,6 @@ function defaultShouldRetry(
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays execution for a specified number of milliseconds.
|
||||
* @param ms The number of milliseconds to delay.
|
||||
* @returns A promise that resolves after the delay.
|
||||
*/
|
||||
function delay(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retries a function with exponential backoff and jitter.
|
||||
* @param fn The asynchronous function to retry.
|
||||
@@ -95,6 +88,10 @@ export async function retryWithBackoff<T>(
|
||||
fn: () => Promise<T>,
|
||||
options?: Partial<RetryOptions>,
|
||||
): Promise<T> {
|
||||
if (options?.signal?.aborted) {
|
||||
throw createAbortError();
|
||||
}
|
||||
|
||||
if (options?.maxAttempts !== undefined && options.maxAttempts <= 0) {
|
||||
throw new Error('maxAttempts must be a positive number.');
|
||||
}
|
||||
@@ -112,6 +109,7 @@ export async function retryWithBackoff<T>(
|
||||
shouldRetryOnError,
|
||||
shouldRetryOnContent,
|
||||
retryFetchErrors,
|
||||
signal,
|
||||
} = {
|
||||
...DEFAULT_RETRY_OPTIONS,
|
||||
...cleanOptions,
|
||||
@@ -122,6 +120,9 @@ export async function retryWithBackoff<T>(
|
||||
let consecutive429Count = 0;
|
||||
|
||||
while (attempt < maxAttempts) {
|
||||
if (signal?.aborted) {
|
||||
throw createAbortError();
|
||||
}
|
||||
attempt++;
|
||||
try {
|
||||
const result = await fn();
|
||||
@@ -132,13 +133,17 @@ export async function retryWithBackoff<T>(
|
||||
) {
|
||||
const jitter = currentDelay * 0.3 * (Math.random() * 2 - 1);
|
||||
const delayWithJitter = Math.max(0, currentDelay + jitter);
|
||||
await delay(delayWithJitter);
|
||||
await delay(delayWithJitter, signal);
|
||||
currentDelay = Math.min(maxDelayMs, currentDelay * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.name === 'AbortError') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const errorStatus = getErrorStatus(error);
|
||||
|
||||
// Check for Pro quota exceeded error first - immediate fallback for OAuth users
|
||||
@@ -243,7 +248,7 @@ export async function retryWithBackoff<T>(
|
||||
`Attempt ${attempt} failed with status ${delayErrorStatus ?? 'unknown'}. Retrying after explicit delay of ${delayDurationMs}ms...`,
|
||||
error,
|
||||
);
|
||||
await delay(delayDurationMs);
|
||||
await delay(delayDurationMs, signal);
|
||||
// Reset currentDelay for next potential non-429 error, or if Retry-After is not present next time
|
||||
currentDelay = initialDelayMs;
|
||||
} else {
|
||||
@@ -252,7 +257,7 @@ export async function retryWithBackoff<T>(
|
||||
// Add jitter: +/- 30% of currentDelay
|
||||
const jitter = currentDelay * 0.3 * (Math.random() * 2 - 1);
|
||||
const delayWithJitter = Math.max(0, currentDelay + jitter);
|
||||
await delay(delayWithJitter);
|
||||
await delay(delayWithJitter, signal);
|
||||
currentDelay = Math.min(maxDelayMs, currentDelay * 2);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user