-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move callbacks to Events. Start separating logic more.
- Loading branch information
Showing
8 changed files
with
194 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import createCallback from '../createCallback'; | ||
|
||
const [getLogger, registerLogHandler] = createCallback(); | ||
const [triggerConnectivityResumed, onConnectivityResumed] = createCallback(); | ||
const [onRequest, registerRequestHandler] = createCallback(); | ||
const [onResponse, registerResponseHandler] = createCallback(); | ||
const [onError, registerErrorHandler] = createCallback(); | ||
const [triggerRecheckNeeded, registerConnectionCheckCallback] = createCallback(); | ||
const [onRequestSkipped, registerRequestSkippedHandler] = createCallback(); | ||
|
||
export { | ||
registerLogHandler, | ||
getLogger, | ||
triggerConnectivityResumed, | ||
onConnectivityResumed, | ||
onRequest, | ||
registerRequestHandler, | ||
onResponse, | ||
registerResponseHandler, | ||
onError, | ||
registerErrorHandler, | ||
triggerRecheckNeeded, | ||
registerConnectionCheckCallback, | ||
registerRequestSkippedHandler, | ||
onRequestSkipped, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import _ from 'underscore'; | ||
import Onyx from 'react-native-onyx'; | ||
import * as NetworkRequestQueue from '../actions/NetworkRequestQueue'; | ||
import * as NetworkStore from './NetworkStore'; | ||
import * as NetworkEvents from './NetworkEvents'; | ||
import CONST from '../../CONST'; | ||
import ONYXKEYS from '../../ONYXKEYS'; | ||
import * as ActiveClientManager from '../ActiveClientManager'; | ||
import processRequest from './processRequest'; | ||
|
||
let persistedRequestsQueueRunning = false; | ||
|
||
/** | ||
* This method will get any persisted requests and fire them off in parallel to retry them. | ||
* If we get any jsonCode besides 407 the request is a success. It doesn't make sense to | ||
* continually retry things that have returned a response. However, we can retry any requests | ||
* with known networking errors like "Failed to fetch". | ||
* | ||
* @returns {Promise} | ||
*/ | ||
function process() { | ||
const persistedRequests = NetworkRequestQueue.getPersistedRequests(); | ||
|
||
// This sanity check is also a recursion exit point | ||
if (NetworkStore.getIsOffline() || _.isEmpty(persistedRequests)) { | ||
return Promise.resolve(); | ||
} | ||
|
||
const tasks = _.map(persistedRequests, request => processRequest(request) | ||
.then((response) => { | ||
if (response.jsonCode === CONST.JSON_CODE.NOT_AUTHENTICATED) { | ||
NetworkEvents.getLogger().info('Persisted optimistic request needs authentication'); | ||
} else { | ||
NetworkEvents.getLogger().info('Persisted optimistic request returned a valid jsonCode. Not retrying.'); | ||
} | ||
NetworkEvents.onResponse(request, response); | ||
NetworkRequestQueue.removeRetryableRequest(request); | ||
}) | ||
.catch((error) => { | ||
// If we are catching a known network error like "Failed to fetch" allow this request to be retried if we have retries left | ||
if (error.message === CONST.ERROR.FAILED_TO_FETCH) { | ||
const retryCount = NetworkRequestQueue.incrementRetries(request); | ||
NetworkEvents.getLogger().info('Persisted request failed', false, {retryCount, command: request.command, error: error.message}); | ||
if (retryCount >= CONST.NETWORK.MAX_REQUEST_RETRIES) { | ||
NetworkEvents.getLogger().info('Request failed too many times removing from storage', false, {retryCount, command: request.command, error: error.message}); | ||
NetworkRequestQueue.removeRetryableRequest(request); | ||
} | ||
} else if (error.name === CONST.ERROR.REQUEST_CANCELLED) { | ||
NetworkEvents.getLogger().info('Persisted request was cancelled. Not retrying.'); | ||
NetworkEvents.onError(request); | ||
NetworkRequestQueue.removeRetryableRequest(request); | ||
} else { | ||
NetworkEvents.getLogger().alert(`${CONST.ERROR.ENSURE_BUGBOT} unknown error while retrying persisted request. Not retrying.`, { | ||
command: request.command, | ||
error: error.message, | ||
}); | ||
NetworkRequestQueue.removeRetryableRequest(request); | ||
} | ||
})); | ||
|
||
// Do a recursive call in case the queue is not empty after processing the current batch | ||
return Promise.all(tasks) | ||
.then(process); | ||
} | ||
|
||
function flush() { | ||
if (persistedRequestsQueueRunning) { | ||
return; | ||
} | ||
|
||
// NETWORK_REQUEST_QUEUE is shared across clients, thus every client/tab will have a copy | ||
// It is very important to only process the queue from leader client otherwise requests will be duplicated. | ||
if (!ActiveClientManager.isClientTheLeader()) { | ||
return; | ||
} | ||
|
||
persistedRequestsQueueRunning = true; | ||
|
||
// Ensure persistedRequests are read from storage before proceeding with the queue | ||
const connectionId = Onyx.connect({ | ||
key: ONYXKEYS.NETWORK_REQUEST_QUEUE, | ||
callback: () => { | ||
Onyx.disconnect(connectionId); | ||
process() | ||
.finally(() => persistedRequestsQueueRunning = false); | ||
}, | ||
}); | ||
} | ||
|
||
// Flush the queue when the connection resumes | ||
NetworkEvents.onConnectivityResumed(flush); | ||
|
||
export { | ||
// eslint-disable-next-line import/prefer-default-export | ||
flush, | ||
}; |
Oops, something went wrong.