Skip to content

Commit

Permalink
feat(client): send retry count header (#493)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-app[bot] authored and Stainless Bot committed Sep 19, 2024
1 parent 6d7f768 commit f202eef
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
16 changes: 12 additions & 4 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,10 @@ export abstract class APIClient {
return null;
}

buildRequest<Req>(options: FinalRequestOptions<Req>): { req: RequestInit; url: string; timeout: number } {
buildRequest<Req>(
options: FinalRequestOptions<Req>,
{ retryCount = 0 }: { retryCount?: number } = {},
): { req: RequestInit; url: string; timeout: number } {
const { method, path, query, headers: headers = {} } = options;

const body =
Expand Down Expand Up @@ -292,7 +295,7 @@ export abstract class APIClient {
headers[this.idempotencyHeader] = options.idempotencyKey;
}

const reqHeaders = this.buildHeaders({ options, headers, contentLength });
const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });

const req: RequestInit = {
method,
Expand All @@ -311,10 +314,12 @@ export abstract class APIClient {
options,
headers,
contentLength,
retryCount,
}: {
options: FinalRequestOptions;
headers: Record<string, string | null | undefined>;
contentLength: string | null | undefined;
retryCount: number;
}): Record<string, string> {
const reqHeaders: Record<string, string> = {};
if (contentLength) {
Expand All @@ -330,6 +335,8 @@ export abstract class APIClient {
delete reqHeaders['content-type'];
}

reqHeaders['x-stainless-retry-count'] = String(retryCount);

this.validateHeaders(reqHeaders, headers);

return reqHeaders;
Expand Down Expand Up @@ -381,13 +388,14 @@ export abstract class APIClient {
retriesRemaining: number | null,
): Promise<APIResponseProps> {
const options = await optionsInput;
const maxRetries = options.maxRetries ?? this.maxRetries;
if (retriesRemaining == null) {
retriesRemaining = options.maxRetries ?? this.maxRetries;
retriesRemaining = maxRetries;
}

await this.prepareOptions(options);

const { req, url, timeout } = this.buildRequest(options);
const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });

await this.prepareRequest(req, { url, options });

Expand Down
30 changes: 30 additions & 0 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,36 @@ describe('retries', () => {
expect(count).toEqual(3);
});

test('retry count header', async () => {
let count = 0;
let capturedRequest: RequestInit | undefined;
const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise<Response> => {
count++;
if (count <= 2) {
return new Response(undefined, {
status: 429,
headers: {
'Retry-After': '0.1',
},
});
}
capturedRequest = init;
return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } });
};

const client = new Mux({
tokenId: 'my token id',
tokenSecret: 'my secret',
fetch: testFetch,
maxRetries: 4,
});

expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 });

expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toEqual('2');
expect(count).toEqual(3);
});

test('retry on 429 with retry-after', async () => {
let count = 0;
const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise<Response> => {
Expand Down

0 comments on commit f202eef

Please sign in to comment.