packager: GlobalTransformCache: retry 502 and 503 HTTP statuses
Reviewed By: davidaurelio Differential Revision: D4818997 fbshipit-source-id: b31b004939f9e83c8a3a8c34b07c8b1ae2d4d17e
This commit is contained in:
parent
b12f6db0ef
commit
03892d1036
|
@ -144,10 +144,17 @@ class TransformProfileSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FetchFailedDetails =
|
||||||
|
{+type: 'unhandled_http_status', +statusCode: number} | {+type: 'unspecified'};
|
||||||
|
|
||||||
class FetchFailedError extends Error {
|
class FetchFailedError extends Error {
|
||||||
constructor(message) {
|
/** Separate object for details allows us to have a type union. */
|
||||||
|
+details: FetchFailedDetails;
|
||||||
|
|
||||||
|
constructor(message: string, details: FetchFailedDetails) {
|
||||||
super();
|
super();
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
(this: any).details = details;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,31 +230,49 @@ class GlobalTransformCache {
|
||||||
const response = await fetch(uri, {method: 'GET', timeout: 8000});
|
const response = await fetch(uri, {method: 'GET', timeout: 8000});
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
const msg = `Unexpected HTTP status: ${response.status} ${response.statusText} `;
|
const msg = `Unexpected HTTP status: ${response.status} ${response.statusText} `;
|
||||||
throw new FetchFailedError(msg);
|
throw new FetchFailedError(msg, {
|
||||||
|
type: 'unhandled_http_status',
|
||||||
|
statusCode: response.status,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const unvalidatedResult = await response.json();
|
const unvalidatedResult = await response.json();
|
||||||
const result = validateCachedResult(unvalidatedResult);
|
const result = validateCachedResult(unvalidatedResult);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new FetchFailedError('Server returned invalid result.');
|
throw new FetchFailedError('Server returned invalid result.', {type: 'unspecified'});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It happens from time to time that a fetch timeouts, we want to try these
|
* It happens from time to time that a fetch fails, we want to try these again
|
||||||
* again a second time.
|
* a second time if we expect them to be transient. We might even consider
|
||||||
|
* waiting a little time before retring if experience shows it's useful.
|
||||||
*/
|
*/
|
||||||
static fetchResultFromURI(uri: string): Promise<CachedResult> {
|
static fetchResultFromURI(uri: string): Promise<CachedResult> {
|
||||||
return GlobalTransformCache._fetchResultFromURI(uri).catch(error => {
|
return GlobalTransformCache._fetchResultFromURI(uri).catch(error => {
|
||||||
if (!GlobalTransformCache.isTimeoutError(error)) {
|
if (!GlobalTransformCache.shouldRetryAfterThatError(error)) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
return this._fetchResultFromURI(uri);
|
return this._fetchResultFromURI(uri);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static isTimeoutError(error: Error): boolean {
|
/**
|
||||||
return error instanceof FetchError && error.type === 'request-timeout';
|
* We want to retry timeouts as they're likely temporary. We retry 503
|
||||||
|
* (Service Unavailable) and 502 (Bad Gateway) because they may be caused by a
|
||||||
|
* some rogue server, or because of throttling.
|
||||||
|
*
|
||||||
|
* There may be other types of error we'd want to retry for, but these are
|
||||||
|
* the ones we experienced the most in practice.
|
||||||
|
*/
|
||||||
|
static shouldRetryAfterThatError(error: Error): boolean {
|
||||||
|
return (
|
||||||
|
error instanceof FetchError && error.type === 'request-timeout' || (
|
||||||
|
error instanceof FetchFailedError &&
|
||||||
|
error.details.type === 'wrong_http_status' &&
|
||||||
|
(error.details.statusCode === 503 || error.details.statusCode === 502)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldFetch(props: FetchProps): boolean {
|
shouldFetch(props: FetchProps): boolean {
|
||||||
|
|
Loading…
Reference in New Issue