Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix connection drop is not detected #7825

Merged

Conversation

kidroca
Copy link
Contributor

@kidroca kidroca commented Feb 19, 2022

Details

Update NetInfo usage to test for internet connectivity rather than active network connection
Desktop specific NetInfo shim is removed - the external issue in the comment has been resolved and offline state is detected in Desktop

Remains the same:

  • When network is lost offline state is detected instantly (like turning off wifi or enabling airplane mode)

New:

  • If internet is unavailable it it takes a bit of time to be detected - up to 12 seconds - when we have a request
    running for +7 seconds we trigger connection recheck that takes about 5 sec. (or less if it fails immediately)
  • When internet is resumed it may take up to 10 sec. to detect, depends on platform

Fixed Issues

$ #6059

Tests

  • Test network connection being correctly detected as offline
  • Test network connection being correctly detected as online

Web / Desktop

  • Open dev tools
  • Set network state to offline from dev tools or turn of wifi

iOS / Android

  • simulate poor network conditions (available in Android emulator)
  • For iOS I think it's only possible on a physical device

QA Steps

Try to simulate very poor or no network conditions

  • Test network connection being correctly detected as offline
  • Test network connection being correctly detected as online

Web / Desktop

  • Use on a tethered connection
  • Use with wifi disabled (cable unplugged)
  • Connected to a connection with no internet (e.g. internet disabled from router)

iOS / Android

  • Try in airplane mode
  • Try with mobile data disabled and no wifi
  • Connection with no internet (e.g. internet disabled from router)

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Web

⚠️ It was only possible to test turning network off because of the web proxy on DEV. When deployed to staging it should work like in the Desktop video

New.Expensify.-.Google.Chrome.2022-02-19.05-37-48.mp4

Mobile Web

mobile.internet.mp4

Desktop

Desktop.Internet.mp4

iOS

RPReplay_Final1645250899.mp4

Android

Android.Internet.mp4

@kidroca kidroca force-pushed the kidroca/fix/connection-drop-is-not-detected branch 2 times, most recently from ddea1cb to ca7cc09 Compare February 19, 2022 03:09
libs/NetInfo served to provide shim for Electron due to an issue
The issue is now resolved and this is no longer needed
Regarding the breaking change - we're not using SSID information - it doesn't affect us

v8 Includes the following fixes:
8.0.0 (2022-02-10)

BREAKING CHANGES
it's possible this is a breaking change, depending on your app use case. If you relied on iOS SSID information and met Apple's strict criteria for accessing SSID, you need to set the new config value shouldFetchWiFiSSID to true. If you set it to true and do not meet the criteria your app may crash due to a memory leak. All versions prior to 7.1.12 would attempt to fetch the information regardless of permission, leak memory, and possibly crash. This change avoids that crash.

Bug Fixes
ios: avoid memory leak from ssid APIs by adding explicit config (Expensify#560) (fbf7c15), closes Expensify#420

7.1.11 (2022-02-08)
Bug Fixes
windows: fix race condition in WiFi connection details feature (Expensify#568) (0cd8132)

7.1.10 (2022-02-07)
Bug Fixes
android: use registerDefaultNetworkCallback so toggling airplane mode works (Expensify#571) (e8af2de)

7.1.9 (2022-01-26)
Bug Fixes
android: count native listeners / correctly disable listener if count == 0 (Expensify#569) (5ae16f6)

7.1.8 (2022-01-25)
Bug Fixes
windows: refactor implementation to avoid crashes (Expensify#564) (cc4bfa3)

7.1.7 (2021-12-20)
Bug Fixes
android: populate network value during initial module startup (Expensify#553) (c05080f)

7.1.6 (2021-12-13)
Bug Fixes
android: avoid send event when has no listener (Expensify#548) (cad47d8)

7.1.5 (2021-12-09)
Bug Fixes
android: use method-local ref to instance var for multi-thread safety Expensify#549 (Expensify#550) (81bbc87)

7.1.4 (2021-12-07)
Bug Fixes
android: try async state fetch as stale state workaround (Expensify#547) (937cf48), closes Expensify#542
This is primarily to help local development and desktop
By default on web (desktop) the url for checking is `/`
And for local testing you'll always hit it matching localhost:8080
For Desktop since the app is served from electron - requesting `/`
would respond with OK even if there's no internet
@kidroca kidroca force-pushed the kidroca/fix/connection-drop-is-not-detected branch from a8b85a3 to f5a0171 Compare February 19, 2022 06:43
@kidroca kidroca marked this pull request as ready for review February 19, 2022 07:00
@kidroca kidroca requested a review from a team as a code owner February 19, 2022 07:00
@MelvinBot MelvinBot removed the request for review from a team February 19, 2022 07:00
src/libs/NetworkConnection.js Outdated Show resolved Hide resolved
src/libs/NetworkConnection.js Outdated Show resolved Hide resolved
src/libs/Network.js Outdated Show resolved Hide resolved
src/CONST/index.js Outdated Show resolved Hide resolved
Copy link
Contributor Author

@kidroca kidroca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I ask what's the problem with defining duration as 10 * 1000 is it against code conventions?

src/libs/NetworkConnection.js Outdated Show resolved Hide resolved
@kidroca
Copy link
Contributor Author

kidroca commented Feb 21, 2022

Ready for review

@parasharrajat
Copy link
Member

parasharrajat commented Feb 21, 2022

Can I ask what's the problem with defining duration as 10 * 1000

It is very clear that 10000 is 10 sec. It is just an extra calculation. Why do you think 10 * 1000 is better?

@kidroca
Copy link
Contributor Author

kidroca commented Feb 22, 2022

It is very clear that 10000 is 10 sec. It is just an extra calculation. Why do you think 10 * 1000 is better?

Maybe for you. I have hard time distinguishing thousands without some kind of visual separator:

  • 10000 (This is looking like 100 000 to me)
  • vs
  • 10,000
  • 10 * 1000

It's common to use this pattern even for seconds: https://github.com/react-native-netinfo/react-native-netinfo/blob/6b01fee211df160d0afce70c5955681c75b24a5a/src/internal/defaultConfiguration.web.ts#L3-L12

And we used as well: https://github.com/Expensify/App/search?q=expiration+%3D+1000+*+60

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind 10 * 1000. I just thinking that we use 5000 ,3000 and not 5 * 1000 in other places of our app.

it makes more sense to use when you have to show the different parts of calculations.
e.g.
Secs in day = 24 * 60 * 60

src/libs/Network.js Show resolved Hide resolved
// whether a user has internet connectivity or not.
unsubscribeFromNetInfo = NetInfo.addEventListener((state) => {
Log.info('[NetworkConnection] NetInfo state', false, state);
setOfflineStatus(!state.isInternetReachable);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we set the offline/online status based on isInternetReachable prop. I didn't find many details about it but I think this flag is set based on the result of the HTTP request.
So when the user is online it seems right to check the flag but when the user is offline it will take some time to be set.
I think we should do this.

if state.isConnected
then offline status = !state.isInternetReachable
Else if !state.isConnected
then offline status = false.

When a user is not connected then we don't have to wait for this flag state.isInternetReachable. If it behaves the same then It's OK.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isInternetReachable is not always set from the result of a request
When state.isConnected is false - state.isInternetReachable is also false

isInternetReachable is set from true to false when the check request fails or takes longer than 5sec.

@kidroca
Copy link
Contributor Author

kidroca commented Feb 25, 2022

✔️ Ready for review

@parasharrajat
Copy link
Member

Ok, I see. I will test it shortly.

@parasharrajat
Copy link
Member

parasharrajat commented Feb 27, 2022

Thanks for the clarification and changes. Looks better now.

Issue 3: If you do above till 4, you will notice that wait time is very high.

Do you think we can improve this by adding a global listener for NetInfo?

 // whether a user has internet connectivity or not.
    unsubscribeFromNetInfo = NetInfo.addEventListener((state) => {
        Log.info('[NetworkConnection] NetInfo state', false, state);
        setOfflineStatus(!state.isInternetReachable);

@kidroca
Copy link
Contributor Author

kidroca commented Feb 28, 2022

Issue 3: If you do above till 4, you will notice that wait time is very high.

Do you think we can improve this by adding a global listener for NetInfo?

How would that help?

@parasharrajat
Copy link
Member

Oh, So we always have an active listener Didn't notice it earlier. At this point, I say we are good.

Copy link
Member

@parasharrajat parasharrajat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

cc: @pecanoro

🎀 👀 🎀 C+ reviewed

@kidroca
Copy link
Contributor Author

kidroca commented Mar 3, 2022

@pecanoro can you review this PR, it's been waiting for some time

@pecanoro
Copy link
Contributor

pecanoro commented Mar 4, 2022

Sure, sorry for the delay, I was at a college career fair during the week so I wasn't on my computer.

@pecanoro pecanoro merged commit 4b80ab6 into Expensify:main Mar 4, 2022
@OSBotify
Copy link
Contributor

OSBotify commented Mar 4, 2022

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@kidroca
Copy link
Contributor Author

kidroca commented Mar 4, 2022

Thank you 👍

@kidroca kidroca deleted the kidroca/fix/connection-drop-is-not-detected branch March 7, 2022 09:52
@marcaaron
Copy link
Contributor

Just a heads up that this is causing CORS errors on dev where most internal engineers are using ngrok to tunnel to the local API. Is there any solution around this?

@kidroca
Copy link
Contributor Author

kidroca commented Mar 8, 2022

Is there any solution around this?

Use a different URL here:

// By default, for web (including Electron) NetInfo uses `/` for `reachabilityUrl`
// When App is served locally or from Electron this would respond with OK even with no internet
// Using API url ensures reachability is tested over internet
reachabilityUrl: CONFIG.EXPENSIFY.URL_API_ROOT,

Or disable the internet reachability test if ENV is DEV

@kidroca
Copy link
Contributor Author

kidroca commented Mar 8, 2022

Shouldn't URL_API_ROOT be the ngrok URL?

const expensifyURLRoot = useNgrok && ngrokURL ? ngrokURL : expensifyComWithProxy;
...
URL_API_ROOT: expensifyURLRoot,

@marcaaron
Copy link
Contributor

Yes, but it seems there's some kind of CORS issue with doing that

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by @pecanoro in version: 1.1.42-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@marcaaron marcaaron added the DeployBlockerCash This issue or pull request should block deployment label Mar 11, 2022
@marcaaron
Copy link
Contributor

Throwing a deploy blocker on here temporarily while we try to figure out what is happening. I have a feeling these changes may be contributing to the instability brought up in this thread

@marcaaron marcaaron removed the DeployBlockerCash This issue or pull request should block deployment label Mar 11, 2022
@marcaaron
Copy link
Contributor

Ok, seems like it is only affecting dev 😄

@OSBotify
Copy link
Contributor

🚀 Deployed to production by @chiragsalian in version: 1.1.42-6 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅


Log.info('[NetworkConnection] recheck NetInfo');
hasPendingNetworkCheck = true;
unsubscribeFromNetInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kidroca Do you recall why you chose to unsubscribe and resubscribe to NetInfo rather than using NetInfo.fetch to recheck the network connection?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, looks like NetInfo will only trigger the recheck if you call NetInfo.fetch with a specific interface: https://github.com/react-native-netinfo/react-native-netinfo/blob/f05f7dd6e829135d907506e9270e729066b6e5d1/src/internal/state.ts#L100-L106

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, looks like NetInfo will only trigger the recheck if you call NetInfo.fetch with a specific interface

Yes, there isn't an exposed way to force a recheck, it might not be necessary, though we decided to do it if any request is taking unusually long time (more than 10-15 sec)

What triggers the recheck is actually the call to NetInfo.configure

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there isn't an exposed way to force a recheck

Yep, I created a PR for react-native-netinfo to add this and clean up this implementation a bit: react-native-netinfo/react-native-netinfo#594

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants