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

Starting app first time without network connection prevents events being pushed to Segment #901

Closed
simon-westman-uba opened this issue Dec 1, 2023 · 12 comments
Labels
bug Something isn't working 🚧 Work In Progress

Comments

@simon-westman-uba
Copy link

simon-westman-uba commented Dec 1, 2023

I have noticed that if I install the app, but open it the very first time without any internet connection, so that the Segment SDK gets initialized without internet connection, no events will ever be pushed to Segment for that session, even after I regain internet connection again.
It is first after I restart the app that events are getting into Segment again, but only for the new session after the restart. The events that should have been created and pushed during the very first session that started without internet connection are lost for ever.

I can see these logs when running locally on iOS, which might be related to this issue:

Connection 13: received failure notification
Connection 13: failed to connect 1:50, reason 18 446 744 073 709 551 615
Connection 13: encountered error(1:50)
Task <9D428989-9D90-4661-8C10-18A09448F79B>.<2> HTTP load failed, 0/0 bytes (error code: 18 446 744 073 709 550 607 [1:50])
Task <9D428989-9D90-4661-8C10-18A09448F79B>.<2> finished with error [18 446 744 073 709 550 607] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x280501ad0 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50, _NSURLErrorNWResolutionReportKey=Resolved 0 endpoints in 2ms using unknown from cache, _NSURLErrorNWPathKey=unsatisfied (No network route)}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <9D428989-9D90-4661-8C10-18A09448F79B>.<2>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <9D428989-9D90-4661-8C10-18A09448F79B>.<2>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://cdn-settings.segment.com/v1/projects/Ui9dSUFlcu71Jnur5FOfyLWvI3xbIKwm/settings, NSErrorFailingURLKey=https://cdn-settings.segment.com/v1/projects/Ui9dSUFlcu71Jnur5FOfyLWvI3xbIKwm/settings, _kCFStreamErrorDomainKey=1}
'An internal error occurred: ', '{"type":3,"innerError":{},"statusCode":-1}'
'Could not receive settings from Segment. Device mode destinations will be ignored unless you specify default settings in the client config.'

The workaround I currently implemented for this is to check for internet connection before initializing the Segment SDK, and if it is the very first start of the app I do not initialize the SDK until internet connection is available through a network listener.
Any subsequent start of the app, after the Segment SDK has been initialized successfully with internet connection, does work as expected even without internet connection.

Also, I could not find anything about this in the documentation. If this was a known issue I would at least expect the documentation to state "Please make sure to have internet connection the first time you initialize the SDK".

  • analytics-react-native version:
"@react-native-async-storage/async-storage": "1.19.7",
"@segment/analytics-react-native": "2.17.0",
"@segment/sovran-react-native": "1.0.4",
  • Integrations versions (if used):
  • React Native version:
"react": "18.2.0",
"react-native": "0.71.11",
  • iOS or Android or both?:
    Both Android and iOS.
    Tested on Galaxy S21 5G with Android 13 and iPhone 11 with iOS 17.0.2

Steps to reproduce

  1. Install your app containing the Segment SDK (but don't open it)
  2. Enable airplane mode
  3. Open your app
  4. Wait for Segment SDK to be initialized in your code
  5. Disable airplane mode (and wait for phone to connect to internet)
  6. No events will be pushed to Segment

Expected behavior

I would expect to see events being pushed to Segment after step 5 since internet connection will be available again at that point.

Actual behavior

No events at all are being pushed to Segment.
I have to restart the app, and only any new events will be pushed after the restart.

@simon-westman-uba simon-westman-uba added the bug Something isn't working label Dec 1, 2023
@oscb
Copy link
Contributor

oscb commented Dec 4, 2023

@simon-westman-uba Hey Simon, this is super detailed and good report, I appreciate the time to test this out.

We already have an idea of what's going on, it's not an intended behavior. I put this up on our sprint to get this fixed

@simon-westman-uba
Copy link
Author

Thank you very much. I will keep an eye out for any upcoming updates and hope you will be able to solve this rather easy.

@alanjcharles
Copy link
Contributor

Hi @simon-westman-uba apologies for the confusion and/or delay here. As @oscb said, thank you for the detailed report, we really do appreciate it. Can you let me know if this is an issue you're still experiencing? If so, we will prioritize it over the next sprint. Thank you for your patience

@simon-westman-uba
Copy link
Author

Hi @alanjcharles I do still see this issue as explained above. Thank you for looking into this.

@leethree
Copy link
Contributor

We are seeing the same issue. It affects our iPhone users in China because they need to accept a special network permission dialog like this before the app having access to the internet.

image

It seems even after the user granted the internet access, the Segment SDK still won't send the events during the app session.

@alanjcharles is there any chance this can be prioritized?

@alanjcharles
Copy link
Contributor

hi folks- apologies for the delays here; we've had some turnover we're working through so we really appreciate your patience. I definitely understand the need to get this prioritized. To get started, can i ask if you have tried the solution we provide here in our readme? It's not super easy to find as it is a Flush Policy example for preventing flushes when no network is detected so here is the example code:

import NetInfo from "@react-native-community/netinfo";

const policiesIfNetworkIsUp = [
  new CountFlushPolicy(5),
  new TimerFlushPolicy(500),
];

// Create our client with our policies by default
const client = createClient({
  // ...
  flushPolicies: policies,
});

// If we detect the user disconnects from the network remove all flush policies, 
// that way we won't keep attempting to send events to segment but we will still 
// store them for future upload.
// If the network comes back up we add the policies back
const unsubscribe = NetInfo.addEventListener((state) => {
  if (state.isConnected) {
    client.addFlushPolicy(...policiesIfNetworkIsUp);
  } else {
    client.removeFlushPolicy(...policiesIfNetworkIsUp)
  }
});

please let me know your thoughts on this and we can go from there. Thanks again! @leethree @simon-westman-uba

@leethree
Copy link
Contributor

@alanjcharles Hi Alan, thank you for the update. I haven't tried the flush policy but I don't think it will work in our case because if the SDK failed to get the settings from Segment server, it won't send the events when flushing.

@alanjcharles
Copy link
Contributor

hi @leethree @simon-westman-uba thanks for the follow-ups. I am actively looking into this and have a few things I'd like to discuss.

  1. it does look like @oscb made a change in an attempt to correct this behavior, here. To be honest, this was initially where I also thought things would be breaking down based on the bug you described- so can you confirm you are on the latest version @segment/[email protected] ?

  2. If you are still seeing the same behavior on the latest version, would you mind sharing any tips you have for successfully reproducing this on an iOS simulator? I have had some luck editing the launch scheme in xcode and using Little Snitch to turn off network traffic, but it's not the easiest situation to reproduce.

Thanks, looking forward to hearing from you!

@leethree
Copy link
Contributor

  1. Yes we are on 2.19.2. The PR seem to store the events if initialisation fail but I think the events won't get reported until the next time the app is cold launched, which could be hours later, or the user might never come back. So we are still missing events for the 1st ever user session, which is arguably the most important events for our app.

  2. I used Proxyman to block traffic to Segment when the app starts. And then enable the traffic later.

Hope this helps!

@alanjcharles
Copy link
Contributor

alanjcharles commented Jul 26, 2024

Hi @leethree Thanks! If I understand your last comment correctly, your issue is not the same as the one initially listed. In the initial post, the issue was the events created during that initial session were never sent to Segment, even when the user did log back into/load the app What you are describing is events from the initial session being sent, just at an undetermined time. I understand that may not be ideal, but there is really nothing we can do to account for that. It is not possible for us to flush or send events to an endpoint if there is no internet connection. Instead, you should manually call flush() as soon as a user grants permission to access in the internet.

Since what you are describing is not actual data loss, I would recommend reaching out to [email protected] for more help in understanding all of the config, flush, and batching options you have available in this SDK to get the data off the device in a more efficient way for your use-case.

If i have misunderstood and you are experiencing actual data loss (as in the events never make it to Segment) please let me know and we can go from there. Thanks!

@simon-westman-uba
Copy link
Author

simon-westman-uba commented Jul 30, 2024

@alanjcharles Thank you so much for looking into this.

So I have been testing this again with the following versions:

  • analytics-react-native version:
"@react-native-async-storage/async-storage": "1.23.1",
"@segment/analytics-react-native": "2.19.2",
"@segment/sovran-react-native": "1.1.1",
  • React Native version:
"react": "18.2.0",
"react-native": "0.73.8",

And I still experience the exact same issue as described in the initial description, on both Android and iOS. I do confirm that the issue still is that the events from the initial launch of the app while offline are lost completely, even after I restart with internet connection.

I tested the flush policies method as you described. I did one try with initializing with the flush policies but removing them when network disappears and adding them back when network appears again, just as described in the docs you linked. But since I, for this test, always start without internet I also did one test where I always initialize with passing an empty array to flushPolicies:

const client = createClient({
  // ...
  flushPolicies: [],
});
NetInfo.addEventListener((state) => {
  if (state.isConnected) {
    client.addFlushPolicy(...policiesIfNetworkIsUp);
  } else {
    client.removeFlushPolicy(...policiesIfNetworkIsUp)
  }
});

Both of these tests failed as well, on both Android and iOS, resulting in the same issue where the events from the initial launch are completely lost.

Unfortunately I do not have any tips for debugging this. The only way I have managed to reproduce this is by doing a Release build of my app and test it on a physical device, because then I can do it in the following order:

  1. Install app from testflight/apptester (but do not launch!)
  2. Enable Airplane mode
  3. Launch app
  4. Wait for SDK to be initialized
  5. Disable Airplane mode

This gets a bit trickier in Debug since you need the JS code to be on the device while being offline. And even if you get the JS code bundled into your build you still need to see the logs. One thing I can think of is to make your computer connect to a Wifi that does not have access to the internet. In that way the Metro bundler should still work on the local network but the app will never have access to the internet. I am not sure if that would produce the same issue/error in the Segment SDK initialization, but could be worth a shot.

@alanjcharles
Copy link
Contributor

Hi @simon-westman-uba no problem at all, happy to help where I can! Thank you for the detailed overview of your debugging process. It is super helpful.

Would you be able to copy your last comment and send it to [email protected]? This will kick off a conversation with out support engineering team who has the time and resources necessary to replicate your environment (as closely as possible), assist with in-depth testing, and offer potential solutions to suit your bespoke use-case. If a bug is uncovered in that process they will also be able to escalate it to our engineering team accordingly.

In an attempt to keep things organized, we are trying to keep reports on this repository to strictly black & white bug reports or enhancements/feature requests. Thanks so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working 🚧 Work In Progress
Projects
None yet
Development

No branches or pull requests

4 participants