Huge freezes/lags when using automatic instrumentation with react-navigation & expo
Platform:
- [X ] iOS
- [ ] Android
SDK:
- [ X]
@sentry/react-native(>= 1.0.0) - [ ]
react-native-sentry(<= 0.43.2)
SDK version: 5.19.1
react-native version: 0.73.4
Are you using Expo?
- [ X] Yes
- [ ] No
Are you using sentry.io or on-premise?
- [ X] sentry.io (SaaS)
- [ ] on-premise
If you are using sentry.io, please post a link to your issue so we can take a look:
Hard to send a link since it's related to freezes and slow performances
Configuration:
(@sentry/react-native)
import { createNavigationContainerRef, ParamListBase } from "@react-navigation/native";
const routingInstrumentation = new Sentry.ReactNavigationInstrumentation();
Sentry.init({
_experiments: {
profilesSampleRate: 0.3
},
attachScreenshot: true,
beforeBreadcrumb: (breadcrumb, hint) => {
if (breadcrumb.category !== "xhr") return breadcrumb;
if (
hint.xhr?.responseURL?.includes("logs") ||
hint.xhr?.responseURL?.includes("generate_204") ||
hint.xhr?.responseURL?.includes("symbolicate") ||
hint.xhr?.responseURL?.includes("amplitude")
) {
return null;
}
const xhr = hint.xhr;
const data = {
requestBody: xhr.__sentry_xhr_v3__?.body,
response: xhr.response,
responseUrl: xhr.responseURL
};
return { ...breadcrumb, data };
},
beforeSend(
event,
hint: {
originalException: {
response: { data: { code: string }; request: { responseURL: string }; status: number };
};
}
) {
const status = hint.originalException?.response?.status;
const code =
hint.originalException?.response?.data?.code ?? (status === 502 ? "502 Bad Gateway" : "Unknown Code");
const url = hint.originalException?.response?.request?.responseURL?.replace(/[0-9]+/g, "X");
if (status && code && url) {
event.fingerprint = [url, status.toString(), code];
}
return event;
},
debug: __DEV__,
dsn: Constants.expoConfig.extra.sentryDSN,
enabled: Constants.expoConfig.extra.appEnv !== ENV.DEVELOPMENT,
integrations: [
new Sentry.ReactNativeTracing({
routingInstrumentation
})
],
tracesSampleRate: 1
});
export const navigationRef = createNavigationContainerRef<ParamListBase>();
<NavigationContainer
linking={{
config,
getInitialURL: async () => {
const url = await Linking.getInitialURL();
setDeepLink(url);
return url;
},
prefixes: [schemeURL, universalLinkPrefix]
}}
onReady={() => {
routingInstrumentation.registerNavigationContainer(navigationRef);
}}>
ref={navigationRef}
>
I have the following issue:
When I add the integration Sentry.ReactNativeTracing with the routing instrumentation for react navigation with the setup above (you will notice that my ref is not created using useRef but with createNavigationContainerRef from react-navigation because I need it for other things in my app), things start to be very slow and I'm experiencing huge freezes when navigating across my screens especially when I'm navigation through my tabs.
Actual result:
- Experiencing multiple freezes when navigating across my screens (especially my tabs)
Expected result:
- I should not experience any performance degradations
Hi @yonitou,
thank you for the message,
could you try to run the application without profiling to check if the freezes are related to profiling load or the navigation instrumentation it self.
Would you be able to reproduce this in an example app or share a link to some recorded sentry profiles for us to inspect. You can use my email address [email protected] or Discord if you can share the link publicly.
I tried the following :
- Without profiling and without route instrumentation : everything works fine
- Without profiling and WITH route instrumentation : huge freezes
- With profiling and without route instrumentation (current setup) : everything works fine
- With profile and with route instrumentation : huge freezes I don't know how to share a complete profile session but when I go to profiling tab, I found my tests from yesterday when I experienced my issue : https://alvie.sentry.io/profiling/profile/hygo-team/170c9a01c9094aa0958ed5e5cda4c30f/flamegraph/?colorCoding=by+system+vs+application+frame&fov=0%2C5%2C806486976%2C20&query=&sorting=call+order&tid=301078&view=bottom+up
Thanks for testing and the link @yonitou! We'll need to investigate and follow up here
Thanks a lot :) waiting for your feedbacks. I hope my profiling link will help.
Hi @yonitou, sadly we do not see any suspicious calls in the profile.
To narrow down what is causing the freezes/lags, could you try to disable some of the tracing features?
new Sentry.ReactNativeTracing({
routingInstrumentation,
enableStallTracking: false,
})
Could you also share how you measure the freezes or do you observe them when testing the application?
Hi @krystofwoldrich I just tried with enableStallTracking at false, it changes nothing. I made a screen recording of my app with and without the instrumentation. I'm running it on my expo development build so it's not really "smooth" but you will see a huge difference between both recordings. I've enabled the react native performance monitoring panel in the top if it can help
The first one is WITHOUT the instrumentation. You can see that it's quite smooth (the development build is never as smooth as a production one in my case) and the switch between tabs is almost instantaneous and the feedback is immediate https://github.com/getsentry/sentry-react-native/assets/61981305/4282a661-1df3-49f9-80b5-e7ffdb8ec292
This one is WITH the instrumentation on ! Look at those freezes. You can't see it (because the screen recording doesn't show my finger taps) but when you see me waiting on a screen, it's because I'm trying to navigate through my tabs but I don't have any feedback, the app is completely stuck and then, getting unstuck at some point.. https://github.com/getsentry/sentry-react-native/assets/61981305/bbb09b1b-4416-4347-8339-3e09b7404167
Does it help ?
Hi @yonitou, this is super useful for us to understand what is happening, but sadly it's it doesn't help with debugging the issue.
From the second video the JS thread is pinned to 60 FPS which is suspicious since the other video show dropping frame rate. Do you observe anything in the JS Console logs during the freeze? Is there any Sentry log just before/after the freeze? Or the console doesn't freeze?
Would you be able to reproduce this in a sample app that you could share with us, so we can debug it?
Hey Sorry for the delay. I have maybe more "clues" to give you :
- The first one is that everytime I'm launching my app in dev mode with sentry enabled, I've the warning
Sentry Logger [warn]: You appear to have multiple versions of the "promise" package installed. This may cause unexpected behavior like undefinedPromise.allSettled. Please install thepromisepackage manually using the exact version as the React Native package. See https://docs.sentry.io/platforms/react-native/troubleshooting/ for more details. - Next, it looks like that once I navigated once or twice on every Tab screen, the navigation is smooth again. It's like I had to navigate at least once to "register" the screen on first mount (it's at this moment that the lags I'm experiencing are happening)
- Lastly, I tried to isolate which logs are related to the freeze. It's hard to say because a lot of logs are coming in debug mode but from what I can tell it's exactly here because the freeze is also present in my JS console.
Sentry Logger [log]: [NativeFrames] Could not fetch native frames for navigation transaction MileosScreen. Not adding native frames measurements.
LOG Sentry Logger [log]: [TouchEvents] Touch event within element: Text
LOG Sentry Logger [log]: [ReactNativeTracing] User Interaction Tracing is disabled.
LOG Sentry Logger [log]: Setting idle transaction on scope. Span ID: 9652cc4888f34dc1
LOG Sentry Logger [log]: [Tracing] starting navigation transaction - Route Change
LOG Sentry Logger [log]: Starting heartbeat
LOG Sentry Logger [log]: pinging Heartbeat -> current counter: 0
LOG Sentry Logger [log]: [Profiling] Skip profiling transaction due to sampling.
LOG Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
LOG Sentry Logger [log]: [NativeFrames] Native frames timed out for navigation transaction MileosScreen. Not adding native frames measurements.
LOG Sentry Logger [log]: [Tracing] finishing IdleTransaction 2024-05-24T14:23:51.825Z navigation
Does it help ?
Thank you @yonitou, based on the latest logs, it might be related to the native frames fetch.
Could you try to disable it to confirm the theory.
new Sentry.ReactNativeTracing({
routingInstrumentation,
enableNativeFramesTracking: false,
})
Not changing anything :/
I just made a new test to isolate the freezing logs. Here's the result :
Sentry Logger [log]: [Profiling] Created profile 029df61546b944efaeedba61ab4eecdd for transaction 1687c8de7fec4d3e830cb9f61dc1bfa4
--------> ITS FREEZING HERE <------------
LOG Sentry Logger [log]: [Tracing] popActivity 91fb63bd155d2a9b
LOG Sentry Logger [log]: [Tracing] new activities count 0
LOG Sentry Logger [log]: [TouchEvents] Touch event within element: Text
LOG Sentry Logger [log]: [ReactNativeTracing] User Interaction Tracing is disabled.
LOG Sentry Logger [log]: Setting idle transaction on scope. Span ID: a055041d9ace9a45
LOG Sentry Logger [log]: [Tracing] starting navigation transaction - Route Change
LOG Sentry Logger [log]: Starting heartbeat
LOG Sentry Logger [log]: pinging Heartbeat -> current counter: 0
LOG Sentry Logger [log]: [NATIVE] Start Profiling
LOG Sentry Logger [log]: [Profiling] started profiling: 76ec72d0b2e543178d24014d84efec26
LOG Sentry Logger [log]: [ReactNativeTracing] Starting navigation transaction "Route Change" on scope
LOG Sentry Logger [log]: [Tracing] pushActivity: 992ea3b3f17cf3b1
LOG Sentry Logger [log]: [Tracing] new activities count 1
@yonitou Thank you for the log, this would point to the profile creation, does it consistently freeze at the same place in the logs? Where does it freeze without profiling?
When disabling profiling, remove the option profilesSampleRate, as setting it to 0 will run the profiler but not sample any profile.
Hi,
I made another test with profilesSampleRate at 0 and enableNativeFramesTracking at false : the freezes are still here but it's hard to say where it freezes in the logs.
BUT I think I understood something : if I'm waiting for the log Sentry Logger [log]: [Tracing] Finishing navigation transaction: XXXXX, and then navigating, it's working smoothly but if I navigate to a tab and then navigate really quick to another tab BEFORE the first transaction is finished, this is freezing ! Does it help ?
Hi, @yonitou thank you for the details, this narrows the investigation, we will keep you updated.
I am also experiencing this same issue. Is there an update on this or ideas to fix this?
@millro04 We are still investigation this.
Would you be able to share any detail about your case? This could help us narrow down the scope of the investigation.
What platform are you experiencing this on, are you using performance and profiling, does it happen on a particular navigation or on all?
@millro04 We are still investigation this.
Would you be able to share any detail about your case? This could help us narrow down the scope of the investigation.
What platform are you experiencing this on, are you using performance and profiling, does it happen on a particular navigation or on all?
We are experiencing this on both iOS and Android. It seems to happen on all navigation. As soon as we disable Sentry, our app speeds up by a significant amount. Otherwise the app becomes very laggy and navigation seems to take 2-3 seconds each time.
Here is some of our config in pseudocode:
const routingInstrumentation = new Sentry.ReactNavigationInstrumentation();
....
// integrations is in the Sentry.init config
integrations: [
new Sentry.ReactNativeTracing({
routingInstrumentation,
tracingOrigins: [
'API_URL_1',
'API_URL_2',
],
}),
],
...
routingInstrumentation.registerNavigationContainer(navigationRef);
@millro04 Thank you for the details.
For what it's worth, I think I found the culprit, at least with my configuration specifically. We are using Sentry redux enhancer, and as soon as I disabled that, the app performance was back to normal. If I turn Sentry redux enhancer back on, the app performs significantly slower.
const sentryReduxEnhancer = Sentry.createReduxEnhancer({
// Optionally pass options listed below
});
const middlewares = [thunk];
const rootReducer = createRootReducer();
const middleware = composeWithDevTools(
applyMiddleware(networkMiddleware, ...middlewares),
sentryReduxEnhancer,
);
// Removing sentryReduxEnhancer from the middleware solves the issue
export const store = createStore(rootReducer, undefined, middleware);
export const persistor = persistStore(store);
We were using a normalizeDepth of 10, and when changing that to a lower value like 3, it does improve performance a bit but it's still slow
@millro04 Thank you for this insight, do you see any changes in speed between attachReduxState: true and attachReduxState: false?
@krystofwoldrich thanks for the follow up! Unfortunately no improvement with changing attachReduxState to false
@millro04 Thank you for the update.
Hi @millro04 and @yonitou would you be able to replicate the slow navigation in a minimal reproducible example which you could share with us to debug?
Since we can't reproduce the issue I'm closing this. In case there is a new context or reproducible example, please, comment here and we can reopen it.
We also ran into a similar issue with slow navigation and general freezing and lag, that was particularly pronounced on android; our app uses react navigation and redux, with quite a large redux state tree. The issue also went away for us when we disabled the redux enhancer.
Thankfully, it looks like as of version 6.0.0 that includes several updates of the redux enhancer included in sentry-js version 8, the issue is fixed.
There is still an issue with sentry and expo-router (react-navigation). Screen transitions between tabs remain laggy, when the required setup code is added:
`const navigationRef = useNavigationContainerRef(); React.useEffect(() => { if (navigationRef) { routingInstrumentation.registerNavigationContainer(navigationRef); } }, [navigationRef]);
export default Sentry.wrap(AppEntryLayout);`
"expo": "51.0.39", "@sentry/react-native": "~5.24.3", (Also tested with 5.35.0 and 6.5.0)
It's not super straightforward to create a lean repro. I'll keep trying but for now see the videos from a release build on a physical device. On low-end devices (ZTE Blade A73.) it materializes more clearly.