Comments (17)
Let me know how to reproduce it.
I believe the problem is likely in your own code due to use of await
somewhere.
the plug-in is very careful to execute its actions in non-blocking background-threads.
from react-native-background-geolocation.
Thank you for your quick response. You're right that the issue might be in our implementation. After reviewing our code, I've identified some areas where we're using await
that could potentially cause blocking behavior. Here's a more detailed breakdown of our implementation:
- We're using
await
in ouronLocation
callback:
const onLocation: Subscription = BackgroundGeolocation.onLocation(
async (location: Location) => {
BackgroundGeolocation.startBackgroundTask().then(
async (taskId: any) => {
try {
// ... (some code omitted for brevity)
// Save the telemetry to Realm
await realmManager.performWithRealm(realm => {
realm.write(() => {
realm.create(
'Telemetry',
{
id: location.uuid,
data: JSON.stringify(telemetryData),
synced: false,
},
UpdateMode.All,
);
});
});
// Process the telemetry queue
await this.processTelemetryQueue();
} catch (error) {
// ... (error handling)
} finally {
await BackgroundGeolocation.stopBackgroundTask(taskId);
}
},
);
},
);
- Our
processTelemetryQueue
method also usesawait
:
private async processTelemetryQueue() {
await this.acquireProcessingLock('processTelemetryQueue', async () => {
try {
const isConnected = await isInternetReachable();
if (isConnected) {
// ... (processing logic)
await this.processTelemetryBatch(telemetryItems);
}
} catch (error) {
// ... (error handling)
}
});
}
- We're also using
await
in ourgetCurrentPosition
method:
public getCurrentPosition = async (
options: CurrentPositionRequest,
): Promise<Location | undefined> => {
if (this._enabled) {
return await BackgroundGeolocation.getCurrentPosition(options);
}
return undefined;
};
To reproduce the issue:
- Initialize our GeolocationService
- Start location tracking
- The app receives location updates frequently (every few seconds)
- Each update triggers the
onLocation
callback, which starts a background task - The background task saves data to Realm and attempts to process the telemetry queue
- If internet is available, it tries to sync the data
The hang occurs during this process, specifically in the queue:type:
method of TSLocationManager
.
Given your feedback, it seems our use of await
in these areas might be causing the main thread to block. Do you have any recommendations on how we should restructure our code to avoid this issue? Should we be handling these operations differently to ensure they don't block the main thread?
We appreciate any guidance you can provide to help us resolve this issue.
I'd like to provide some context on why we've structured our code this way:
-
Metadata Requirements:
We need to attach specific metadata to each telemetry point. This metadata includes information such as the current job status, device information, and other contextual data that's critical for our business logic. This metadata can change between location updates, so we need to ensure it's captured at the exact moment of the location update. -
Offline Functionality:
Our app needs to function in offline scenarios. When the device goes offline, we continue to collect location data along with the associated metadata. This data is stored locally using Realm. -
Historical Context:
When the device comes back online, we need to sync not just the current location, but all the stored offline data. Each of these historical data points needs to maintain its original metadata. If we were to only use current metadata when syncing, we'd lose the historical context of each location update, which is crucial for our tracking requirements. -
Data Integrity:
By processing each location update synchronously (usingawait
), we ensure that the metadata associated with each location point is accurate for that specific moment in time. This helps maintain data integrity across our system. -
Complex Sync Logic:
OurprocessTelemetryQueue
method needs to handle various scenarios, including partial syncs, retries, and ensuring data is synced in the correct order. This complexity led us to implement it as an async function.
We understand that this approach might not be optimal for performance, especially given the frequent location updates. We're open to suggestions on how to restructure our code to maintain these requirements while improving performance and avoiding potential hangs.
Some questions we have:
- Is there a recommended way to attach custom metadata to each location update without blocking the main thread?
- How can we ensure that offline data is properly stored and synced with its original metadata when the device comes back online?
- Are there best practices for handling complex, stateful operations (like our sync logic) in the context of background geolocation?
We're eager to improve our implementation and would greatly appreciate any insights or recommendations you can provide based on these specific requirements.
from react-native-background-geolocation.
Hello @christocracy ! Thank you for helping us here. I really appreciate it.
Looks like the code that was sent is no up to date.
I don't have access to the TSLocation class as it's already compiled but unless you wait there for message form js with a lock until it happens I don't see how await could cause any deadlock. The BackgroundLocation native module which is bridge based without any synchronous calls.
When you send event to Js or resolve a promise it happens asynchronously.
We have 2 appHang events that took over 2s (It doesn't necessarily mean it was a deadlock) it could be just operation on the main thread that made UI thread unresponsive for over 2s.
In both cases looks like TSLocation gets "didUpdateLocations" event from he os (on the main thread)
And another thread (TSQueue) is executing getCurrentPosition call. (asynchronous from what I see)
from react-native-background-geolocation.
Create for me a simple “hello-world” app which reproduces this. Share it with me in a public GitHub repo
from react-native-background-geolocation.
Create for me a simple “hello-world” app which reproduces this. Share it with me in a public GitHub repo
We will try. At the moment we are not sure what exact sequence of events causes the issue. Our theory is that the problem is caused by a call to getCurrentPosition() while we also have an onLocation() listener.
from react-native-background-geolocation.
Nobody has reported this in 9 years. I believe it’s your own code blocking the UI thread.
from react-native-background-geolocation.
Nobody has reported this in 9 years. I believe it’s your own code blocking the UI thread.
Thanks. Just to clarify: does this mean it should be OK to call getCurrentPosition() while an onLocation() listener is active?
from react-native-background-geolocation.
@christocracy If you check the stack trace of the main thread (First stacktrace) you see that the only thing on the main thread is the TSLocationManager code. If there is a deadlock that is caused by us that would mean that TSLocationManager on the main thread is waiting for a resource that we locked. What that could be?
Could you share a code of this method [TSLocationManager queue:type:]?
from react-native-background-geolocation.
It's also possible that there is no deadlock at all and that method for some weird reason takes over 2s.
from react-native-background-geolocation.
Start disabling your code until the problem goes away.
from react-native-background-geolocation.
@christocracy, thank you for your input. We've analyzed the situation further:
- The hang occurs within
TSLocationManager queue:type:
, which is part of the plugin's compiled code. - Main thread stack trace shows only TSLocationManager code during the hang.
- Issue appears when
onLocation()
listener is active andgetCurrentPosition()
is called concurrently. - We're working on a minimal reproduction app, but the intermittent nature makes it challenging.
- Can you review the
queue:type:
method for potential thread safety issues? - Are there additional diagnostics we can enable in the plugin for more detailed information?
- Is it safe to call
getCurrentPosition()
while anonLocation()
listener is active?
We're open to further investigation on our end. Please advise on specific areas to examine or modify for testing.
from react-native-background-geolocation.
Why would you call .getCurrentPosition in your onLocation event-handler?? That would create an infinite loop.
from react-native-background-geolocation.
Your analysis of the native code is a red herring. There’s nothing wrong with the native code.
from react-native-background-geolocation.
@christocracy, thank you for your follow-up. To clarify:
- We're not calling
getCurrentPosition
within theonLocation
handler. These are separate operations in our app. getCurrentPosition
is a method provided by your library that we use independently of theonLocation
events.- Our usage:
- We have
onLocation
set up to receive regular updates. - Separately, we occasionally call
getCurrentPosition
for immediate location data.
- We have
- The hang occurs during normal operation, not in an infinite loop scenario.
- Metadata handling: We need to attach custom metadata to each location update. This metadata can change between updates and is crucial for our offline functionality and historical context. How can we efficiently attach this metadata without risking performance issues or crashes?
Can you suggest best practices for using getCurrentPosition
alongside onLocation
in your library? We want to ensure we're not inadvertently creating conflicts.
from react-native-background-geolocation.
Can you suggest best practices for using getCurrentPosition alongside onLocation in your library?
Don’t. Ever. .getCurrentPosition CAUSES .onLocation events to be fired. Why would you request a new location in an event-handler which just provided you a location?!
from react-native-background-geolocation.
@christocracy, I apologize for any confusion. Let me clarify our situation:
- We are NOT calling
getCurrentPosition
within theonLocation
handler. These are separate, independent operations in our app. - The issue occurs during normal operation where:
- We have
onLocation
set up for regular updates. - Separately and occasionally, we call
getCurrentPosition
for immediate location data.
- We have
- We've identified a potential deadlock in your library:
- One thread is waiting on the UI thread using
dispatch_sync_f_slow
- The UI thread is then trying to acquire a lock with
objc_sync_enter
- This lock seems to be already held by the first thread, causing a deadlock
- One thread is waiting on the UI thread using
- Stack traces for reference:
Thread 1:libdispatch +0x1181c _dispatch_sync_f_slow
-><***> +0xabfc44 -[TSQueue runOnMainQueueWithoutDeadlocking:]
Main thread:libobjc.A +0x51b8 objc_sync_enter
-><***> +0xa98e34 -[TSLocationManager queue:type:]
- Our main concerns remain:
- Efficiently attaching custom metadata to each location update
- Resolving crashes originating from the transistorsoft library
Could you please advise on:
a) Best practices for using getCurrentPosition
alongside onLocation
without conflicts
b) Efficient methods for attaching custom metadata to location updates
c) Strategies to investigate and resolve the crashes we're experiencing
from react-native-background-geolocation.
As I said, nobody has reported a problem like this in 9 years. Create for me a simple hello-world app which reproduces this issue. Share it with me in a public GitHub repo.
from react-native-background-geolocation.
Related Issues (20)
- State change HOT 12
- Question about preventSuspend HOT 5
- Basic Doubts HOT 6
- Expo integration HOT 6
- Post Payload Optimization HOT 2
- Permissions in Background Tracking HOT 5
- Start Tracking on Closed Application HOT 8
- Permissions
- StopTimeout not Working HOT 13
- Background Location not detecting on few devices like Oneplus , Apple Iphone 15 pro HOT 3
- Background Location not detecting on few devices like Oneplus , Apple Iphone 15 pro HOT 1
- Background Location Stop Detecting Very Late After Stopped HOT 1
- Background Location Stop Detecting Very Late After Stopped HOT 4
- java.lang.IncompatibleClassChangeError upon update from Expo SDK 49 to 51 HOT 1
- The operation couldn’t be completed. Background procssing task was not registered in AppDelegate didFinishLaunchingWithOptions. See iOS Setup Guide. HOT 1
- Realtime Database Firebase HOT 10
- Strange background location indicator - can't turn off HOT 4
- onEnabled and onGeofence not triggering on production but does work on development HOT 2
- Schedule is not working as expected in IOS HOT 11
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-native-background-geolocation.