Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/shared-fetch-utils/common/middleware/serverErrorBackoffMiddleware.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { FetchBlockedError, type FetchMiddleware } from '../fetchTypes';
7
8
export class ServerBackoffError extends FetchBlockedError {
9
constructor(retryAfterMs: number) {
10
super(`Backing off for ${Math.round(retryAfterMs / 1000)}s after server error`, retryAfterMs);
11
}
12
}
13
14
export interface BackoffOptions {
15
readonly initialDelayMs?: number;
16
readonly maxDelayMs?: number;
17
readonly multiplier?: number;
18
}
19
20
/**
21
* After a `5xx` response, blocks subsequent requests for an exponentially
22
* increasing duration. The backoff resets on the first successful response.
23
*/
24
export function serverErrorBackoffMiddleware(options?: BackoffOptions): FetchMiddleware {
25
const { initialDelayMs = 1_000, maxDelayMs = 60_000, multiplier = 2 } = options ?? {};
26
let consecutiveFailures = 0;
27
let backoffUntil = 0;
28
29
return (next) => async (request) => {
30
if (Date.now() < backoffUntil) {
31
throw new ServerBackoffError(backoffUntil - Date.now());
32
}
33
34
const response = await next(request);
35
36
if (response.status >= 500) {
37
consecutiveFailures++;
38
const delay = Math.min(
39
initialDelayMs * Math.pow(multiplier, consecutiveFailures - 1),
40
maxDelayMs,
41
);
42
backoffUntil = Date.now() + delay;
43
throw new ServerBackoffError(delay);
44
}
45
46
// Success → reset
47
consecutiveFailures = 0;
48
backoffUntil = 0;
49
50
return response;
51
};
52
}
53
54