Skip to content

Commit

Permalink
Merge pull request #41702 from Expensify/arosiclair-deferred-updates-…
Browse files Browse the repository at this point in the history
…loop

[CP Staging] Fix GetMissingOnyxMessages infinite loop when processing deferred updates

(cherry picked from commit a2172a1)
  • Loading branch information
arosiclair authored and OSBotify committed May 6, 2024
1 parent a3035bf commit ac092b4
Showing 1 changed file with 14 additions and 3 deletions.
17 changes: 14 additions & 3 deletions src/libs/actions/OnyxUpdateManager/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Onyx from 'react-native-onyx';
import Log from '@libs/Log';
import * as App from '@userActions/App';
import type {DeferredUpdatesDictionary, DetectGapAndSplitResult} from '@userActions/OnyxUpdateManager/types';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -76,9 +77,11 @@ function detectGapsAndSplit(updates: DeferredUpdatesDictionary, clientLastUpdate

// This function will check for gaps in the deferred updates and
// apply the updates in order after the missing updates are fetched and applied
function validateAndApplyDeferredUpdates(clientLastUpdateID?: number): Promise<void> {
function validateAndApplyDeferredUpdates(clientLastUpdateID?: number, previousParams?: {newLastUpdateIDFromClient: number; latestMissingUpdateID: number}): Promise<void> {
const lastUpdateIDFromClient = clientLastUpdateID ?? lastUpdateIDAppliedToClient ?? 0;

Log.info('[DeferredUpdates] Processing deferred updates', false, {lastUpdateIDFromClient, previousParams});

// We only want to apply deferred updates that are newer than the last update that was applied to the client.
// At this point, the missing updates from "GetMissingOnyxUpdates" have been applied already, so we can safely filter out.
const pendingDeferredUpdates = Object.entries(deferredUpdatesProxy.deferredUpdates).reduce<DeferredUpdatesDictionary>(
Expand All @@ -100,6 +103,8 @@ function validateAndApplyDeferredUpdates(clientLastUpdateID?: number): Promise<v
// If we detected a gap in the deferred updates, only apply the deferred updates before the gap,
// re-fetch the missing updates and then apply the remaining deferred updates after the gap
if (latestMissingUpdateID) {
Log.info('[DeferredUpdates] Gap detected in deferred updates', false, {lastUpdateIDFromClient, latestMissingUpdateID});

return new Promise((resolve, reject) => {
deferredUpdatesProxy.deferredUpdates = {};

Expand All @@ -115,15 +120,21 @@ function validateAndApplyDeferredUpdates(clientLastUpdateID?: number): Promise<v

// If lastUpdateIDAppliedToClient got updated in the meantime, we will just retrigger the validation and application of the current deferred updates.
if (latestMissingUpdateID <= newLastUpdateIDFromClient) {
validateAndApplyDeferredUpdates(clientLastUpdateID)
validateAndApplyDeferredUpdates(undefined, {newLastUpdateIDFromClient, latestMissingUpdateID})
.then(() => resolve(undefined))
.catch(reject);
return;
}

// Prevent info loops of calls to GetMissingOnyxMessages
if (previousParams?.newLastUpdateIDFromClient === newLastUpdateIDFromClient && previousParams?.latestMissingUpdateID === latestMissingUpdateID) {
Log.info('[DeferredUpdates] Aborting call to GetMissingOnyxMessages, repeated params', false, {lastUpdateIDFromClient, latestMissingUpdateID, previousParams});
return;
}

// Then we can fetch the missing updates and apply them
App.getMissingOnyxUpdates(newLastUpdateIDFromClient, latestMissingUpdateID)
.then(() => validateAndApplyDeferredUpdates(clientLastUpdateID))
.then(() => validateAndApplyDeferredUpdates(undefined, {newLastUpdateIDFromClient, latestMissingUpdateID}))
.then(() => resolve(undefined))
.catch(reject);
});
Expand Down

0 comments on commit ac092b4

Please sign in to comment.