Path: blob/main/extensions/copilot/src/shared-fetch-utils/common/middleware/serverErrorBackoffMiddleware.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { FetchBlockedError, type FetchMiddleware } from '../fetchTypes';67export class ServerBackoffError extends FetchBlockedError {8constructor(retryAfterMs: number) {9super(`Backing off for ${Math.round(retryAfterMs / 1000)}s after server error`, retryAfterMs);10}11}1213export interface BackoffOptions {14readonly initialDelayMs?: number;15readonly maxDelayMs?: number;16readonly multiplier?: number;17}1819/**20* After a `5xx` response, blocks subsequent requests for an exponentially21* increasing duration. The backoff resets on the first successful response.22*/23export function serverErrorBackoffMiddleware(options?: BackoffOptions): FetchMiddleware {24const { initialDelayMs = 1_000, maxDelayMs = 60_000, multiplier = 2 } = options ?? {};25let consecutiveFailures = 0;26let backoffUntil = 0;2728return (next) => async (request) => {29if (Date.now() < backoffUntil) {30throw new ServerBackoffError(backoffUntil - Date.now());31}3233const response = await next(request);3435if (response.status >= 500) {36consecutiveFailures++;37const delay = Math.min(38initialDelayMs * Math.pow(multiplier, consecutiveFailures - 1),39maxDelayMs,40);41backoffUntil = Date.now() + delay;42throw new ServerBackoffError(delay);43}4445// Success → reset46consecutiveFailures = 0;47backoffUntil = 0;4849return response;50};51}525354