Skip to content

Commit 9df26d3

Browse files
committed
don't retry if 400 or 401 response code
1 parent 773aacc commit 9df26d3

File tree

3 files changed

+229
-128
lines changed

3 files changed

+229
-128
lines changed

rush-plugins/rush-amazon-s3-build-cache-plugin/src/AmazonS3Client.ts

+55-31
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ interface IIsoDateString {
2929
dateTime: string;
3030
}
3131

32+
type RetriableRequestResponse<T> =
33+
| {
34+
hasNetworkError: true;
35+
error: unknown;
36+
}
37+
| {
38+
hasNetworkError: false;
39+
response: T;
40+
};
41+
3242
const protocolRegex: RegExp = /^https?:\/\//;
3343
const portRegex: RegExp = /:(\d{1,5})$/;
3444

@@ -124,35 +134,60 @@ export class AmazonS3Client {
124134

125135
public async getObjectAsync(objectName: string): Promise<Buffer | undefined> {
126136
this._writeDebugLine('Reading object from S3');
127-
const sendRequest: () => Promise<Buffer | undefined> = async (): Promise<Buffer | undefined> => {
137+
type Response = RetriableRequestResponse<Buffer | undefined>;
138+
const sendRequest: () => Promise<Response> = async (): Promise<Response> => {
128139
const response: fetch.Response = await this._makeRequestAsync('GET', objectName);
129140
if (response.ok) {
130-
return await response.buffer();
141+
return {
142+
hasNetworkError: false,
143+
response: await response.buffer()
144+
};
131145
} else if (response.status === 404) {
132-
return undefined;
146+
return {
147+
hasNetworkError: false,
148+
response: undefined
149+
};
133150
} else if (response.status === 403 && !this._credentials) {
134-
return undefined;
135-
} else {
151+
return {
152+
hasNetworkError: false,
153+
response: undefined
154+
};
155+
} else if (response.status === 400 || response.status === 401 || response.status === 403) {
136156
this._throwS3Error(response, await this._safeReadResponseText(response));
157+
} else {
158+
const error: Error = this._getS3Error(response, await this._safeReadResponseText(response));
159+
return {
160+
hasNetworkError: true,
161+
error
162+
};
137163
}
138164
};
139165

140-
return this._sendCacheRequestWithRetries(sendRequest);
166+
return await this._sendCacheRequestWithRetries(sendRequest);
141167
}
142168

143169
public async uploadObjectAsync(objectName: string, objectBuffer: Buffer): Promise<void> {
144170
if (!this._credentials) {
145171
throw new Error('Credentials are required to upload objects to S3.');
146172
}
147173

148-
const sendRequest: () => Promise<void> = async (): Promise<void> => {
174+
type Response = RetriableRequestResponse<void>;
175+
176+
const sendRequest: () => Promise<Response> = async (): Promise<Response> => {
149177
const response: fetch.Response = await this._makeRequestAsync('PUT', objectName, objectBuffer);
150178
if (!response.ok) {
151-
this._throwS3Error(response, await this._safeReadResponseText(response));
179+
return {
180+
hasNetworkError: true,
181+
error: this._getS3Error(response, await this._safeReadResponseText(response))
182+
};
152183
}
184+
return {
185+
hasNetworkError: false,
186+
response: undefined
187+
};
153188
};
154189

155-
return this._sendCacheRequestWithRetries(sendRequest);
190+
await this._sendCacheRequestWithRetries(sendRequest);
156191
}
157192

158193
private _writeDebugLine(...messageParts: (string | IColorableSequence)[]): void {
@@ -334,14 +369,18 @@ export class AmazonS3Client {
334369
return undefined;
335370
}
336371

337-
private _throwS3Error(response: fetch.Response, text: string | undefined): never {
338-
throw new Error(
372+
private _getS3Error(response: fetch.Response, text: string | undefined): Error {
373+
return new Error(
339374
`Amazon S3 responded with status code ${response.status} (${response.statusText})${
340375
text ? `\n${text}` : ''
341376
}`
342377
);
343378
}
344379

380+
private _throwS3Error(response: fetch.Response, text: string | undefined): never {
381+
throw this._getS3Error(response, text);
382+
}
383+
345384
/**
346385
* Validates a S3 endpoint which is http(s):// + hostname + port. Hostname validated according to RFC 1123
347386
* {@link https://docs.aws.amazon.com/general/latest/gr/s3.html}
@@ -401,25 +440,10 @@ export class AmazonS3Client {
401440
}
402441
}
403442

404-
private async _sendCacheRequestWithRetries<T>(sendRequest: () => Promise<T>): Promise<T> {
405-
type TryResponse = { hasNetworkError: false; response: T } | { hasNetworkError: true; error: unknown };
406-
407-
const trySendRequest: () => Promise<TryResponse> = async (): Promise<TryResponse> => {
408-
try {
409-
const response: T = await sendRequest();
410-
return {
411-
response,
412-
hasNetworkError: false
413-
};
414-
} catch (err) {
415-
return {
416-
hasNetworkError: true,
417-
error: err
418-
};
419-
}
420-
};
421-
422-
const response: TryResponse = await trySendRequest();
443+
private async _sendCacheRequestWithRetries<T>(
444+
sendRequest: () => Promise<RetriableRequestResponse<T>>
445+
): Promise<T> {
446+
const response: RetriableRequestResponse<T> = await sendRequest();
423447

424448
const log: (...messageParts: (string | IColorableSequence)[]) => void = this._writeDebugLine.bind(this);
425449

@@ -441,7 +465,7 @@ export class AmazonS3Client {
441465
}, delay);
442466
});
443467

444-
const response: TryResponse = await trySendRequest();
468+
const response: RetriableRequestResponse<T> = await sendRequest();
445469

446470
if (response.hasNetworkError) {
447471
if (retryAttempt < maxTries - 1) {

0 commit comments

Comments
 (0)