diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
commit | de98e0b232509d5f40c135d540a70e415272ff85 (patch) | |
tree | a79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/fbjs/lib/fetchWithRetries.js.flow | |
parent | e0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff) |
node_modules
Diffstat (limited to 'node_modules/fbjs/lib/fetchWithRetries.js.flow')
-rw-r--r-- | node_modules/fbjs/lib/fetchWithRetries.js.flow | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/node_modules/fbjs/lib/fetchWithRetries.js.flow b/node_modules/fbjs/lib/fetchWithRetries.js.flow new file mode 100644 index 000000000..967f5c376 --- /dev/null +++ b/node_modules/fbjs/lib/fetchWithRetries.js.flow @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule fetchWithRetries + * @typechecks + * @flow + */ + +'use strict'; + +const ExecutionEnvironment = require('./ExecutionEnvironment'); + +const sprintf = require('./sprintf'); +const fetch = require('./fetch'); +const warning = require('./warning'); + +export type InitWithRetries = { + body?: mixed; + cache?: ?string; + credentials?: ?string; + fetchTimeout?: ?number; + headers?: mixed; + method?: ?string; + mode?: ?string; + retryDelays?: ?Array<number>; +}; + +const DEFAULT_TIMEOUT = 15000; +const DEFAULT_RETRIES = [1000, 3000]; + +/** + * Makes a POST request to the server with the given data as the payload. + * Automatic retries are done based on the values in `retryDelays`. + */ +function fetchWithRetries(uri: string, initWithRetries?: ?InitWithRetries): Promise<any> { + const { fetchTimeout, retryDelays, ...init } = initWithRetries || {}; + const _fetchTimeout = fetchTimeout != null ? fetchTimeout : DEFAULT_TIMEOUT; + const _retryDelays = retryDelays != null ? retryDelays : DEFAULT_RETRIES; + + let requestsAttempted = 0; + let requestStartTime = 0; + return new Promise((resolve, reject) => { + /** + * Sends a request to the server that will timeout after `fetchTimeout`. + * If the request fails or times out a new request might be scheduled. + */ + function sendTimedRequest(): void { + requestsAttempted++; + requestStartTime = Date.now(); + let isRequestAlive = true; + const request = fetch(uri, init); + const requestTimeout = setTimeout(() => { + isRequestAlive = false; + if (shouldRetry(requestsAttempted)) { + warning(false, 'fetchWithRetries: HTTP timeout, retrying.'); + retryRequest(); + } else { + reject(new Error(sprintf('fetchWithRetries(): Failed to get response from server, ' + 'tried %s times.', requestsAttempted))); + } + }, _fetchTimeout); + + request.then(response => { + clearTimeout(requestTimeout); + if (isRequestAlive) { + // We got a response, we can clear the timeout. + if (response.status >= 200 && response.status < 300) { + // Got a response code that indicates success, resolve the promise. + resolve(response); + } else if (shouldRetry(requestsAttempted)) { + // Fetch was not successful, retrying. + // TODO(#7595849): Only retry on transient HTTP errors. + warning(false, 'fetchWithRetries: HTTP error, retrying.'), retryRequest(); + } else { + // Request was not successful, giving up. + const error: any = new Error(sprintf('fetchWithRetries(): Still no successful response after ' + '%s retries, giving up.', requestsAttempted)); + error.response = response; + reject(error); + } + } + }).catch(error => { + clearTimeout(requestTimeout); + if (shouldRetry(requestsAttempted)) { + retryRequest(); + } else { + reject(error); + } + }); + } + + /** + * Schedules another run of sendTimedRequest based on how much time has + * passed between the time the last request was sent and now. + */ + function retryRequest(): void { + const retryDelay = _retryDelays[requestsAttempted - 1]; + const retryStartTime = requestStartTime + retryDelay; + // Schedule retry for a configured duration after last request started. + setTimeout(sendTimedRequest, retryStartTime - Date.now()); + } + + /** + * Checks if another attempt should be done to send a request to the server. + */ + function shouldRetry(attempt: number): boolean { + return ExecutionEnvironment.canUseDOM && attempt <= _retryDelays.length; + } + + sendTimedRequest(); + }); +} + +module.exports = fetchWithRetries;
\ No newline at end of file |