Skip to content

Commit 2bc14ce

Browse files
stainless-botRobertCraigie
authored andcommitted
feat(client): adjust retry behavior to be exponential backoff (#400)
1 parent cdee077 commit 2bc14ce

File tree

2 files changed

+10
-14
lines changed

2 files changed

+10
-14
lines changed

src/core.ts

+8-12
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ export {
2727
type Uploadable,
2828
} from './uploads';
2929

30-
const MAX_RETRIES = 2;
31-
3230
export type Fetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
3331

3432
type PromiseOrValue<T> = T | Promise<T>;
@@ -162,7 +160,7 @@ export abstract class APIClient {
162160

163161
constructor({
164162
baseURL,
165-
maxRetries,
163+
maxRetries = 2,
166164
timeout = 600000, // 10 minutes
167165
httpAgent,
168166
fetch: overridenFetch,
@@ -174,7 +172,7 @@ export abstract class APIClient {
174172
fetch: Fetch | undefined;
175173
}) {
176174
this.baseURL = baseURL;
177-
this.maxRetries = validatePositiveInteger('maxRetries', maxRetries ?? MAX_RETRIES);
175+
this.maxRetries = validatePositiveInteger('maxRetries', maxRetries);
178176
this.timeout = validatePositiveInteger('timeout', timeout);
179177
this.httpAgent = httpAgent;
180178

@@ -513,8 +511,6 @@ export abstract class APIClient {
513511
retriesRemaining: number,
514512
responseHeaders?: Headers | undefined,
515513
): Promise<APIResponseProps> {
516-
retriesRemaining -= 1;
517-
518514
// About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
519515
let timeoutMillis: number | undefined;
520516
const retryAfterHeader = responseHeaders?.['retry-after'];
@@ -540,22 +536,22 @@ export abstract class APIClient {
540536
}
541537
await sleep(timeoutMillis);
542538

543-
return this.makeRequest(options, retriesRemaining);
539+
return this.makeRequest(options, retriesRemaining - 1);
544540
}
545541

546542
private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number {
547543
const initialRetryDelay = 0.5;
548-
const maxRetryDelay = 2;
544+
const maxRetryDelay = 8.0;
549545

550546
const numRetries = maxRetries - retriesRemaining;
551547

552548
// Apply exponential backoff, but not more than the max.
553-
const sleepSeconds = Math.min(initialRetryDelay * Math.pow(numRetries - 1, 2), maxRetryDelay);
549+
const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
554550

555-
// Apply some jitter, plus-or-minus half a second.
556-
const jitter = Math.random() - 0.5;
551+
// Apply some jitter, take up to at most 25 percent of the retry time.
552+
const jitter = 1 - Math.random() * 0.25;
557553

558-
return (sleepSeconds + jitter) * 1000;
554+
return sleepSeconds * jitter * 1000;
559555
}
560556

561557
private getUserAgent(): string {

tests/index.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ describe('instantiate client', () => {
135135
});
136136

137137
test('maxRetries option is correctly set', () => {
138-
const client = new OpenAI({ maxRetries: 1, apiKey: 'My API Key' });
139-
expect(client.maxRetries).toEqual(1);
138+
const client = new OpenAI({ maxRetries: 4, apiKey: 'My API Key' });
139+
expect(client.maxRetries).toEqual(4);
140140

141141
// default
142142
const client2 = new OpenAI({ apiKey: 'My API Key' });

0 commit comments

Comments
 (0)