react-native: Fetch API breaks when turning network off and on.
- Review the documentation: https://facebook.github.io/react-native
- Search for existing issues: https://github.com/facebook/react-native/issues
- Use the latest React Native version: https://github.com/facebook/react-native/releases
- Run
react-native infoin your terminal and paste its contents under “Environment” - Let us know how to reproduce the issue. Include a code sample, share a project, or share an app that reproduces the issue using https://snack.expo.io/
Environment
Environment: OS: Linux 4.15 Node: 8.11.1 Yarn: 1.5.1 npm: 5.6.0 Watchman: Not Found Xcode: N/A Android Studio: 3.1 AI-173.4720617
Packages: (wanted => installed) react: 16.3.1 => 16.3.1 react-native: 0.55.4 => 0.55.0
Note: This is the environment where we built RN v0.55.0 from source to reproduce the bug. Originally, we experienced the issue with RN v0.55.4 https://github.com/zulip/zulip-mobile/issues/2287
Description
On Android, calls to fetch() take several minutes after turning the internet connection off and on again.
An initial bug report can be found here: https://github.com/zulip/zulip-mobile/issues/2287. The same report features a detailed comment on how to reproduce the bug in the app it was reported for.
Steps to Reproduce
The issue can be reproduced on Android with the following app:
export default class App extends Component<Props> {
myFunction() {
console.log("Button pressed");
NetInfo.getConnectionInfo().then((connectionInfo) => {
console.log('Initial, type: ' + connectionInfo.type + ', effectiveType: ' + connectionInfo.effectiveType);
});
fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => console.log("response", response))
.catch((error) => {
console.error(error);
});
};
render() {
return (
<View style={styles.container}>
<Button
onPress={this.myFunction}
title="Learn More"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>
);
}
}
I then ran the app on an emulator, clicked the button a couple times and disabled and enabled the network with
$ adb shell svc data disable
$ adb shell svc data enable
Here is the app’s output in Chrome Dev Tools:
Button pressed
12:25:45.945 App.js:29 Initial, type: cellular, effectiveType: 4g
12:25:46.222 App.js:32 response Response {type: "default", status: 200, ok: true, statusText: undefined, headers: Headers, …}
12:25:53.044 App.js:27 Button pressed
12:25:53.053 App.js:29 Initial, type: none, effectiveType: unknown
12:25:58.261 App.js:27 Button pressed
12:25:58.267 App.js:29 Initial, type: cellular, effectiveType: 4g
12:35:46.703 App.js:32 response Response {type: "default", status: 200, ok: true, statusText: undefined, headers: Headers, …}
12:35:46.741 App.js:32 response Response {type: "default", status: 200, ok: true, statusText: undefined, headers: Headers, …}
Two things are interesting about the output above.
- After turning the network off and on and pressing the button, fetch does not receive the resource.
- After waiting for ~10 minutes, two responses come in. One is probably for the request sent out while the app was offline, and the other for the request sent out after the app was brought back online.
I also wrote a little app in Android Studio that uses two buttons and OkHttp to reproduce the issue. Reproduction steps can be found in the repo’s README.md. https://github.com/roberthoenig/react-native-fetch-bug
Expected Behavior
I expect fetch() to work the same before and after turning off and on the internet connection.
In particular, I expect a prompt response to requests I send out.
Actual Behavior
After turning the internet connection off and on, fetch() did not respond promptly. It took ~10 minutes.
In other trials, this varied from ~ 2 - 15 minutes. After investigating RN’s source code, I stumbled upon this
line:
https://github.com/facebook/react-native/blob/d52569c4a1b6bd19792e4bda23e3a8c3ac4ad8df/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L429
I then added
client.connectionPool().evictAll();
before it.
After adding this line, dis- and reconnecting didn’t confuse RN anymore. After reconnecting, requests just work. Oc, this is not a final solution, since client.connectionPool().evictAll(); clears all previous network connections made by this client.
A possible grand unifying theory of what is going on under the hood for this bug:
- I disconnect from the network.
- While offline, some part of the app that we have no influence on makes some network request X.
- X doesn’t get sent out to the internet, because we’re offline. However, the default timeout for X we have no control over is set to 0, meaning “no timeout”.
- I reconnect to the network.
- Because X never got sent out, RN will never receive a response for X. However, the timeout is set to 0, so RN will wait for X forever. Reconnecting to the network won’t change anything for X.
- I make my own request Y. Y gets “enqueued” by the same client that enqueued X, meaning that they’ll share the same connectionPool.
- X needs to be processed before Y can get processed. X blocks Y. This might be our bug.
- At some point in time some random event clears super old connection or something like that. X gets removed. Y gets finally dispatched, but super late.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 28
- Comments: 20 (2 by maintainers)
Commits related to this issue
- networking: Fix requests failing when turning network off and on (#19709). This bug is probably actually a bug in OkHttp: https://github.com/square/okhttp/issues/4079 Both issues linked above contain... — committed to roberthoenig/react-native by roberthoenig 6 years ago
- networking: Fix requests failing when turning network off and on #19709. This bug is probably actually a bug in OkHttp: square/okhttp#4079 Both issues linked above contain extensive details about the... — committed to roberthoenig/react-native by roberthoenig 6 years ago
- networking: Fix requests failing when turning network off and on #19709. This bug is probably actually a bug in OkHttp: square/okhttp#4079 Both issues linked above contain extensive details about the... — committed to roberthoenig/react-native by roberthoenig 6 years ago
- networking: Fix requests failing when turning network off and on #19709. This bug is probably actually a bug in OkHttp: square/okhttp#4079 Both issues linked above contain extensive details about the... — committed to roberthoenig/react-native by roberthoenig 6 years ago
- networking: Fix requests failing when turning network off and on #19709. This bug is probably actually a bug in OkHttp: square/okhttp#4079 Both issues linked above contain extensive details about the... — committed to roberthoenig/react-native by roberthoenig 6 years ago
- networking: Fix requests failing when turning network off and on #19709. This bug is probably actually a bug in OkHttp: square/okhttp#4079 Both issues linked above contain extensive details about the... — committed to roberthoenig/react-native by roberthoenig 6 years ago
- networking: Fix requests failing when turning network off and on #19709. This bug is probably actually a bug in OkHttp: square/okhttp#4079 Both issues linked above contain extensive details about the... — committed to roberthoenig/react-native by roberthoenig 6 years ago
- networking: Fully fix requests failing when turning network off and on #19709. The previous commit partially fixed #19709 by evicting all idle connections on DISCONNECT and CONNECTING events. To full... — committed to roberthoenig/react-native by roberthoenig 6 years ago
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community’s attention? This issue may be closed if no further activity occurs. You may also label this issue as “For Discussion” or “Good first issue” and I will leave it open. Thank you for your contributions.
Yes, this issue is still there. We have experienced it on a specific Android Automotive platform - only the physical device, not the AVD.
It seems to be related to a proxy or some middle layer in the networking stack on the Android which accepts connections even if the network is down but then does not return any results (obviously). That in combination with the implementation of NetworkingModule which only sets the connectTimeout in okhttp instead of the callTimeout seems to cause the calls to hang forever without running the error callback, meaning the JS Promise in RN will never return. AND in combination with the connectionPool, the same broken connection gets used for all subsequent calls.
The correct solution may be to change
in NetworkingModule.java into
but since we did not want to fork RN, we found another solution based on the original post which needed no modification of core RN:
The NetworkingModule accepts a plugged in CustomBuilder which exposes the okhttp state. Use that to insert a connectionPool().evictAll(). Add this to your apps MainApplication.java:
and it works like a charm.
I’m experiencing this issue still on both xhr and fetch on android
react-native@0.59.8fix it please
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.
I have a really hard time with this problem recently. I managed to find out the reason (fetch) though, but cannot get a clear solution. Any further progress on this issue?