diff --git a/native/components/feature-flags-provider.react.js b/native/components/feature-flags-provider.react.js index cd51c7c24..ba9909cc3 100644 --- a/native/components/feature-flags-provider.react.js +++ b/native/components/feature-flags-provider.react.js @@ -1,97 +1,119 @@ // @flow import AsyncStorage from '@react-native-async-storage/async-storage'; import * as React from 'react'; import { Platform } from 'react-native'; import { fetchFeatureFlags } from 'lib/utils/feature-flags-utils.js'; +import sleep from 'lib/utils/sleep.js'; import { useIsCurrentUserStaff } from 'native/utils/staff-utils.js'; import { codeVersion } from '../redux/persist.js'; type FeatureFlagsConfiguration = { +[feature: string]: boolean, }; type FeatureFlagsContextType = { +configuration: FeatureFlagsConfiguration, +loadedFromService: boolean, }; const defaultContext = { configuration: {}, loadedFromService: false, }; const FeatureFlagsContext: React.Context = React.createContext(defaultContext); const featureFlagsStorageKey = 'FeatureFlags'; type Props = { +children: React.Node, }; function FeatureFlagsProvider(props: Props): React.Node { const { children } = props; const isStaff = useIsCurrentUserStaff(); const [featuresConfig, setFeaturesConfig] = React.useState(defaultContext); React.useEffect(() => { (async () => { if (featuresConfig.loadedFromService) { return; } const persistedFeaturesConfig = await AsyncStorage.getItem( featureFlagsStorageKey, ); if (!persistedFeaturesConfig) { return; } setFeaturesConfig(config => config.loadedFromService ? config : { configuration: JSON.parse(persistedFeaturesConfig), loadedFromService: false, }, ); })(); }, [featuresConfig.loadedFromService]); React.useEffect(() => { (async () => { try { - const config = await fetchFeatureFlags( - Platform.OS, - isStaff, - codeVersion, + const config = await tryMultipleTimes( + () => fetchFeatureFlags(Platform.OS, isStaff, codeVersion), + 3, + 5000, ); + const configuration = {}; for (const feature of config.enabledFeatures) { configuration[feature] = true; } setFeaturesConfig({ configuration, loadedFromService: true, }); await AsyncStorage.setItem( featureFlagsStorageKey, JSON.stringify(configuration), ); } catch (e) { console.error('Feature flag retrieval failed:', e); } })(); }, [isStaff]); return ( {children} ); } +async function tryMultipleTimes( + f: () => Promise, + numberOfTries: number, + delay: number, +): Promise { + let lastError; + while (numberOfTries > 0) { + try { + return await f(); + } catch (e) { + --numberOfTries; + lastError = e; + if (numberOfTries > 0) { + await sleep(delay); + } + } + } + throw lastError; +} + export { FeatureFlagsContext, FeatureFlagsProvider, featureFlagsStorageKey };