MOB-988 setup to run unconditional offline experiment

This commit is contained in:
Ryan Stelly
2025-12-01 20:00:03 -06:00
parent 28cd1dd11b
commit 739978441e
5 changed files with 79 additions and 22 deletions

View File

@@ -19,7 +19,10 @@ import _ from "lodash";
import { RealmContext } from "providers/contexts";
import React, {
useCallback,
useEffect, useReducer, useRef, useState
useEffect,
useReducer,
useRef,
useState
} from "react";
import fetchPlaceName from "sharedHelpers/fetchPlaceName";
import saveObservation from "sharedHelpers/saveObservation";
@@ -28,6 +31,7 @@ import {
useExitObservationFlow, useLocationPermission, useSuggestions, useWatchPosition
} from "sharedHooks";
import { isDebugMode } from "sharedHooks/useDebugMode";
import { useShouldFetchOfflineSuggestionsUnconditionally } from "sharedHooks/useSuggestions";
import useStore from "stores/useStore";
import tryToReplaceWithLocalTaxon from "./helpers/tryToReplaceWithLocalTaxon";
@@ -101,6 +105,8 @@ const MatchContainer = ( ) => {
renderPermissionsGate,
requestPermissions
} = useLocationPermission( );
const shouldFetchOfflineSuggestionsUnconditionally
= useShouldFetchOfflineSuggestionsUnconditionally();
const obsPhotos = currentObservation?.observationPhotos;
@@ -141,7 +147,7 @@ const MatchContainer = ( ) => {
|| onlineFetchStatus === FETCH_STATUS_ONLINE_ERROR;
const onFetchError = useCallback(
( { isOnline }: { isOnline: boolean } ) => {
( { isOnline } ) => {
if ( isOnline ) {
dispatch( {
type: "SET_ONLINE_FETCH_STATUS",
@@ -153,7 +159,10 @@ const MatchContainer = ( ) => {
offlineFetchStatus: FETCH_STATUS_OFFLINE_ERROR
} );
// If offline is finished, and online still in loading state it means it never started
if ( onlineFetchStatus === FETCH_STATUS_LOADING ) {
// unless we're intentionally fetching offline unconditionally in the background
if ( onlineFetchStatus === FETCH_STATUS_LOADING
&& !shouldFetchOfflineSuggestionsUnconditionally
) {
dispatch( {
type: "SET_ONLINE_FETCH_STATUS",
onlineFetchStatus: FETCH_STATUS_ONLINE_SKIPPED
@@ -161,11 +170,11 @@ const MatchContainer = ( ) => {
}
}
},
[onlineFetchStatus]
[onlineFetchStatus, shouldFetchOfflineSuggestionsUnconditionally]
);
const onFetched = useCallback(
( { isOnline }: { isOnline: boolean } ) => {
( { isOnline } ) => {
if ( isOnline ) {
dispatch( {
type: "SET_ONLINE_FETCH_STATUS",
@@ -173,17 +182,22 @@ const MatchContainer = ( ) => {
} );
// Currently we start offline only when online has an error, so
// we can register offline as skipped if online is successful
dispatch( {
type: "SET_OFFLINE_FETCH_STATUS",
offlineFetchStatus: FETCH_STATUS_OFFLINE_SKIPPED
} );
// unless we're intentionally fetching offline unconditionally in the background
if ( !shouldFetchOfflineSuggestionsUnconditionally ) {
dispatch( {
type: "SET_OFFLINE_FETCH_STATUS",
offlineFetchStatus: FETCH_STATUS_OFFLINE_SKIPPED
} );
}
} else {
dispatch( {
type: "SET_OFFLINE_FETCH_STATUS",
offlineFetchStatus: FETCH_STATUS_OFFLINE_FETCHED
} );
// If offline is finished, and online still in loading state it means it never started
if ( onlineFetchStatus === FETCH_STATUS_LOADING ) {
// unless we're intentionally fetching offline unconditionally in the background
if ( onlineFetchStatus === FETCH_STATUS_LOADING
&& !shouldFetchOfflineSuggestionsUnconditionally ) {
dispatch( {
type: "SET_ONLINE_FETCH_STATUS",
onlineFetchStatus: FETCH_STATUS_ONLINE_SKIPPED
@@ -191,7 +205,7 @@ const MatchContainer = ( ) => {
}
}
},
[onlineFetchStatus]
[onlineFetchStatus, shouldFetchOfflineSuggestionsUnconditionally]
);
const {
@@ -203,6 +217,7 @@ const MatchContainer = ( ) => {
refetchSuggestions
} = useSuggestions( observationPhoto, {
shouldFetchOnlineSuggestions,
shouldFetchOfflineSuggestionsUnconditionally,
onFetchError,
onFetched,
scoreImageParams,

View File

@@ -28,7 +28,7 @@ export { default as useRemoteObservation } from "./useRemoteObservation";
export { default as useScrollToOffset } from "./useScrollToOffset";
export { default as useShare } from "./useShare";
export { default as useStoredLayout } from "./useStoredLayout";
export { default as useSuggestions } from "./useSuggestions/useSuggestions";
export { useSuggestions } from "./useSuggestions/useSuggestions";
export { default as useTaxon } from "./useTaxon";
export { default as useTaxonSearch } from "./useTaxonSearch";
export { default as useTranslation } from "./useTranslation";

View File

@@ -0,0 +1,6 @@
export {
default as useShouldFetchOfflineSuggestionsUnconditionally
} from "./useShouldFetchOfflineSuggestionsUnconditionally";
export {
default as useSuggestions
} from "./useSuggestions";

View File

@@ -0,0 +1,22 @@
import { useMemo } from "react";
const simultaneousOnlineOfflineSuggestionsEnabled = false;
const simultaneousOnlineOfflinePercentageChance = 1;
const useShouldFetchOfflineSuggestionsUnconditionally = ( ) => {
const fetchOfflineSuggestionsUnconditionally = useMemo(
() => {
if ( !simultaneousOnlineOfflineSuggestionsEnabled ) {
return false;
}
return Math.random() <= simultaneousOnlineOfflinePercentageChance;
},
// This is not exactly x% of suggs but it should be close enough?
// The Screen component is reused across AI Cam uses and doesn't necessarily
// rerender so this would be all suggs on x% of Screen mounts.
[]
);
return fetchOfflineSuggestionsUnconditionally;
};
export default useShouldFetchOfflineSuggestionsUnconditionally;

View File

@@ -1,15 +1,28 @@
import { useNetInfo } from "@react-native-community/netinfo";
import _ from "lodash";
import { useMemo } from "react";
import filterSuggestions from "./filterSuggestions";
import useOfflineSuggestions from "./useOfflineSuggestions";
import useOnlineSuggestions from "./useOnlineSuggestions";
export const useSuggestions = ( photoUri, options ) => {
interface Options {
shouldFetchOnlineSuggestions: boolean;
shouldFetchOfflineSuggestionsUnconditionally?: boolean;
onFetchError: () => void;
onFetched: () => void;
scoreImageParams?: {
lat: number;
lng: number;
};
queryKey: string[];
onlineSuggestionsAttempted: boolean;
}
export const useSuggestions = ( photoUri: string, options: Options ) => {
const { isConnected } = useNetInfo( );
const {
shouldFetchOnlineSuggestions,
shouldFetchOfflineSuggestionsUnconditionally,
onFetchError,
onFetched,
scoreImageParams,
@@ -46,9 +59,11 @@ export const useSuggestions = ( photoUri, options ) => {
const urlWillCrashOffline = photoUri?.includes( "https://" ) && !isConnected;
// skip to offline suggestions if internet connection is spotty
const fallingBackToOfflineSuggestions = timedOut
|| !isConnected
|| ( !onlineSuggestions && onlineSuggestionsAttempted );
const tryOfflineSuggestions = !urlWillCrashOffline && (
timedOut
|| ( !onlineSuggestions && onlineSuggestionsAttempted )
shouldFetchOfflineSuggestionsUnconditionally || fallingBackToOfflineSuggestions
);
const {
@@ -70,13 +85,12 @@ export const useSuggestions = ( photoUri, options ) => {
refetchOfflineSuggestions();
}
};
const usingOfflineSuggestions = tryOfflineSuggestions || (
offlineSuggestions?.results?.length > 0
&& ( !onlineSuggestions || onlineSuggestions?.results?.length === 0 )
);
const hasOnlineSuggestionResults = onlineSuggestions?.results?.length > 0;
const hasOfflineSuggestionResults = offlineSuggestions?.results?.length > 0;
const usingOfflineSuggestions = fallingBackToOfflineSuggestions || (
hasOfflineSuggestionResults && !hasOnlineSuggestionResults && onlineSuggestionsAttempted
);
const unfilteredSuggestions = useMemo(
( ) => ( hasOnlineSuggestionResults