109 lines
3.5 KiB
JavaScript
109 lines
3.5 KiB
JavaScript
import { Platform } from "react-native";
|
|
import BackgroundFetch from "react-native-background-fetch";
|
|
import { createLogger } from "~/lib/logger";
|
|
import { executeHeartbeatSync } from "~/location/backgroundTask";
|
|
|
|
const backgroundFetchLogger = createLogger({
|
|
service: "background-fetch",
|
|
task: "service",
|
|
});
|
|
|
|
/**
|
|
* Initialize BackgroundFetch according to the documentation best practices.
|
|
* This should be called once when the root component mounts.
|
|
*/
|
|
export const initializeBackgroundFetch = async () => {
|
|
try {
|
|
backgroundFetchLogger.info("Initializing BackgroundFetch service");
|
|
|
|
// Configure BackgroundFetch for both platforms
|
|
const status = await BackgroundFetch.configure(
|
|
{
|
|
minimumFetchInterval: 15, // Only valid option - gives best chance of execution
|
|
},
|
|
// Event callback - handles both default fetch events and custom scheduled tasks
|
|
async (taskId) => {
|
|
backgroundFetchLogger.info("BackgroundFetch event received", {
|
|
taskId,
|
|
});
|
|
|
|
let syncResult = null;
|
|
|
|
try {
|
|
// Execute the shared heartbeat logic and get result
|
|
syncResult = await executeHeartbeatSync();
|
|
backgroundFetchLogger.debug("Heartbeat sync completed", {
|
|
syncResult,
|
|
});
|
|
} catch (error) {
|
|
backgroundFetchLogger.error("Heartbeat sync failed", {
|
|
error: error.message,
|
|
taskId,
|
|
});
|
|
} finally {
|
|
// CRITICAL: Always call finish with appropriate result
|
|
try {
|
|
if (taskId) {
|
|
let fetchResult;
|
|
|
|
if (syncResult?.error || !syncResult?.syncSuccessful) {
|
|
// Task failed
|
|
fetchResult = BackgroundFetch.FETCH_RESULT_FAILED;
|
|
} else if (
|
|
syncResult?.syncPerformed &&
|
|
syncResult?.syncSuccessful
|
|
) {
|
|
// Force sync was performed successfully - new data
|
|
fetchResult = BackgroundFetch.FETCH_RESULT_NEW_DATA;
|
|
} else {
|
|
// No sync was needed - no new data
|
|
fetchResult = BackgroundFetch.FETCH_RESULT_NO_DATA;
|
|
}
|
|
|
|
BackgroundFetch.finish(taskId, fetchResult);
|
|
backgroundFetchLogger.debug("BackgroundFetch task finished", {
|
|
taskId,
|
|
fetchResult,
|
|
});
|
|
}
|
|
} catch (finishError) {
|
|
backgroundFetchLogger.error(
|
|
"Failed to finish BackgroundFetch task",
|
|
{
|
|
error: finishError.message,
|
|
taskId,
|
|
},
|
|
);
|
|
}
|
|
}
|
|
},
|
|
// Timeout callback (REQUIRED by BackgroundFetch API)
|
|
async (taskId) => {
|
|
backgroundFetchLogger.warn("BackgroundFetch task timeout", { taskId });
|
|
// CRITICAL: Must call finish on timeout with FAILED result
|
|
try {
|
|
BackgroundFetch.finish(taskId, BackgroundFetch.FETCH_RESULT_FAILED);
|
|
} catch (error) {
|
|
backgroundFetchLogger.error("Failed to finish timed out task", {
|
|
error: error.message,
|
|
taskId,
|
|
});
|
|
}
|
|
},
|
|
);
|
|
|
|
backgroundFetchLogger.info("BackgroundFetch configured successfully", {
|
|
status,
|
|
platform: Platform.OS,
|
|
});
|
|
|
|
return status;
|
|
} catch (error) {
|
|
backgroundFetchLogger.error("Failed to initialize BackgroundFetch", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
platform: Platform.OS,
|
|
});
|
|
throw error;
|
|
}
|
|
};
|