segmentio / analytics-react-native

The hassle-free way to add analytics to your React-Native app.
https://segment.com/docs/sources/mobile/react-native/
MIT License
361 stars 185 forks source link

Supposedly queued event never being sent #649

Closed bill-pairaktaridis closed 1 year ago

bill-pairaktaridis commented 2 years ago

Steps to reproduce The following logs point to my screen event being saved before the Segment client has finalized initializing:

 INFO  SCREEN event saved {"name": "SCREEN NAME", "type": "screen"}
 INFO  Received settings from Segment succesfully.
 INFO  TRACK (Application Opened) event saved {"event": "Application Opened", "properties": {"build": "1", "from_background": false, "version": "7.5.0"}, "type": "track"}

The Application Opened lifecycle method is sent. The screen one is not.

Expected behavior I would expect the queued event to be sent, even if the client hasn't initialized yet.

Actual behavior The "saved" event is never sent

oscb commented 2 years ago

When are you calling the screen event ? Is it tied to a navigation library or is it manually called? Asking to replicate this issue and investigate further

bill-pairaktaridis commented 2 years ago

@oscb no, it's manually called without the hook because of our particular setup

oscb commented 2 years ago

@bill-pairaktaridis Sorry, I haven't been able to replicate this issue in the latest version of the library.

Could you share some extra details on how you are creating your client and calling the screen event? is it during a constructor or rendering a component? Just after creating the client? Any particular settings for flushAt and flushInterval? Any plugins?

Also, when you mention that you don't see the screen event I'm assuming it is that you don't see it in the Segment Debugger, right?

I'm going to close this for our tracking but feel free to reopen if it's still happening and you are able to share more data!

buuuudzik commented 1 year ago

Unfortunately it's still not fixed in v2.10.0.

I've found that when createClient will finish it's job it has isInitialized=false until it will receive a config from Segment servers. In this short period of time every action will be logged to the console but not added to any queue and omitted.

isInitialized is a private method so it can't be used to check if segment client is ready. createClient is synchronous but it looks its nature is not synchronous and it has side effects and at least it should have a method onInit().

AnalyticsProvider won't help in this case because it will render children before it's fully ready to handle events.

But it should be ready for adding events to the queue all the time.

buuuudzik commented 1 year ago

The problem is here: client.init();

It should be await client.init(); and the whole createClient function should be async.

Eventually please create a separate async function createInitializedClient or client.onInit() method because currently there is no 100% reliable way to execute track,screen,identify methods on created client which is not yet initialized.

@oscb Can you help?

oscb commented 1 year ago

init is async by design, we don't intend for users to await for client creation nor block their UI for it since it already has a pending event queue where it stores things before the client is ready to send things (which is actually well before fetchSettings due to persistence playing a part): https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L392 https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L446

Not saying that this is not happening but wondering if it only happens with a particular configuration, hence why I asked before for the configuration and plugins in the client, when/how are you guys instantiating it and when are the events you are missing triggered.

The way I've been trying to repro is just by adding latency to the fetch settings calls on the example and seeing if there's an issue when running on a fresh install vs an already populated install. I'm creating track calls both right after createClient is called and when the first React component renders. All calls go to pending and await until everything in the client is ready before sending to Segment, confirmed this in the debugger.

If you have any plugins added I think that could pinpoint where the concurrency issue is, or any particular configuration that you got would be really helpful.

oscb commented 1 year ago

@buuuudzik any chance you are using the AdvertisingId or IDFA plugins?

buuuudzik commented 1 year ago

@oscb Thanks for your reply! I really appreciate your help.

We're using IdfaPlugin and AppsflyerPlugin plugins but at the moment when @bill-pairaktaridis created this ticket we we've used no plugins.

I don't want to introduce some braking change to your code, just please expose client.onInitialized() method where I can pass a callback which will be executed after segment client will have client.isInitialized=true.

Because I want to run client.track() fully reliably at the very early moment of an app lifecycle.

You can test it in such a way:

const client = createClient(config);
client.track('TEST_EVENT');

You will find a log in console but the event will never be sent to your servers. Maybe you're checking only in logs, please test with your servers or by checking API calls. This could be also related to these plugins but probably not because based on logs this occurs before below line: INFO Received settings from Segment succesfully.

so the problem can occure before segment will fetch its config.

oscb commented 1 year ago

@buuuudzik this is helpful. I'm definitely adding a callback onInitialized like the one you mentioned, there's some technicalities since it doesn't just have to await for .init() but we already have everything in place, just a matter of exposing it.

I particularly asked for IDFA/AdvertisingId because I just noticed those 2 plugins do some operations on their constructors which in the right conditions might make us think that the context has been loaded before it actually is (one of the conditions to start sending events). I'm refactoring that logic.

I'm actually testing it against Segment itself, so I can confirm the events were showing up for me in the cloud, not just on logs. And I'm doing the exact same call as yours. I was not using IDFA nor AF plugins though.

When you say you are not seeing events in your servers do you mean on the Segment Debugger for your source? or in a particular destination?

Can you share your configuration too (except your writeKey) please? I want to double check too if any other configuration can impact this.

One final question and just to confirm: You are only missing events triggered right after createClient right? it is not all events in a session

buuuudzik commented 1 year ago

Yes, we're missing only events triggered right after createClient and before the client.isInitialized is set to true so can't be sure that .

I know also that Segment Debugger can not show all events but I've checked this multiple times and I've checked this also in DB.

buuuudzik commented 1 year ago

@oscb Frankly, I've just tried a few things but I cannot reproduce today this bug. So maybe this was just not presented in 'Segment Debugger' plus too early check in a DB.

But I will make the last test with the same internet connection which I was using when I've found this strange behaviour.

I will let you know about the results.

oscb commented 1 year ago

No worries, if you find the particular conditions when it happens please let me know. Nevertheless I'm still working on exposing the callback for when the client is ready as well as refactoring the concurrency logic of initialization so that it is safer even if you are not awaiting for the callback. This library was already overdue for that.

oscb commented 1 year ago

@buuuudzik I refactored the initialization logic. This should make the system less prone to race conditions which I believe must be what was causing this bug. It was just merged last week, I'll try to release it this week: https://github.com/segmentio/analytics-react-native/pull/765

oscb commented 1 year ago

@buuuudzik Sorry, I forgot to ping back, we release this fix in @segment/analytics-react-native-v2.13.1

Let us know if you see this showing up again.