microsoft / ApplicationInsights-JS

Microsoft Application Insights SDK for JavaScript
MIT License
642 stars 236 forks source link

[Offline Support][BUG] `@microsoft/applicationinsights-offlinechannel-js` - persisted data is not being send when coming online #2368

Open p-hlp opened 1 week ago

p-hlp commented 1 week ago

Description/Screenshot I'm currently trying to get the new offline channel to work so we don't miss any events when users are offline (in a pwa context). I've pretty much followed the implementation in the docs here. When setting offlineListener.setOnlineState(2), I can see that events are being persisted in the chosen storage (in my case local storage with key AIOffline_1_*). When coming back online and by offlineListener.setOnlineState(1) the collected data is not send, even when waiting the maxSentBatchInterval default time of 15s.

Steps to Reproduce

Relevant dep. versions:

    "@microsoft/applicationinsights-react-js": "^17.2.0",
    "@microsoft/applicationinsights-web": "^3.2.2",
    "@microsoft/applicationinsights-offlinechannel-js": "^0.2.2",

(Side-note, we made the conscious decision to use pinned versions, I cannot get this to work however due to same issue described in #95. Need to use semver range, otherwise getting ts build-time errors. Error is: Argument of type 'OfflineChannel' is not assignable to parameter of type 'IPlugin'. Will provide a different issue for that.)

export const offlineChannel = new OfflineChannel();

export const initializeTelemetry = () => { const reactPlugin = new ReactPlugin();

appInsights = new ApplicationInsights({ config: { connectionString: import.meta.env.VITE_APPLICATION_INSIGHTS_CONNECTION_STRING, enableAutoRouteTracking: true, // react-router doesn't expose router history extensions: [reactPlugin], extensionConfig: {

      // INFO eStorageProviders.localStorage = 1 - cannot use const enum with isolatedModules = true, required by vite https://vitejs.dev/guide/features.html#isolatedmodules
      // INFO eStorageProviders.IndexedDB = 3
      providers: [1],
      minPersistanceLevel: EventPersistence.Normal,
    },
  },
  enableCorsCorrelation: true,
},

});

appInsights.loadAppInsights(); appInsights.addPlugin(offlineChannel);

return withAITracking(reactPlugin, RootApp); }


Then just in a different component/page:

```js
const offlineListener = offlineChannel.getOfflineListener();
offlineListener.setOnlineState(1) // online

and likewise

const offlineListener = offlineChannel.getOfflineListener();
offlineListener.setOnlineState(2) // offline

Expected behavior

When coming back online by setting offlineListener.setOnlineState(1), persisted events should be sent to ai.

Additional context Not sure if I'm missing something, since docs say A post or sender channel is required for processing online events. Not quite clear to me whether I need to explicitly register/add this to the app insights instance?

Will provide a repository for repro as soon as I have time.

siyuniu-ms commented 1 week ago

(Side-note, we made the conscious decision to use pinned versions, I cannot get this to work however due to same issue described in https://github.com/microsoft/applicationinsights-react-js/issues/95#issuecomment-2187590553. Need to use semver range, otherwise getting ts build-time errors. Error is: Argument of type 'OfflineChannel' is not assignable to parameter of type 'IPlugin'. Will provide a different issue for that.)

Hi, if you want to use a pinned version, please check this table: https://github.com/microsoft/applicationinsights-react-js?tab=readme-ov-file#compatibility-matrix Make sure you are using the corrsponding version. For example:

    "@microsoft/applicationinsights-react-js": "17.2.0",
    "@microsoft/applicationinsights-web": "3.2.0",
siyuniu-ms commented 1 week ago

, since docs say A post or sender channel is required for processing online events. Not quite clear to me whether I need to explicitly register/add this to the app insights instance?

To clarify:

  1. If you only need to process online events, @microsoft/applicationinsights-web already includes a post channel, so no additional configuration is needed.

  2. If your app will be offline for some time and you want to support telemetry being sent after it comes back online, you should include the offline-channel.

  3. The note is informing users that for packages that do not include a send/post channel, the offline-channel cannot send telemetry on its own. It requires a post/send channel to perform that function.

p-hlp commented 1 week ago

(Side-note, we made the conscious decision to use pinned versions, I cannot get this to work however due to same issue described in microsoft/applicationinsights-react-js#95 (comment). Need to use semver range, otherwise getting ts build-time errors. Error is: Argument of type 'OfflineChannel' is not assignable to parameter of type 'IPlugin'. Will provide a different issue for that.)

Hi, if you want to use a pinned version, please check this table: https://github.com/microsoft/applicationinsights-react-js?tab=readme-ov-file#compatibility-matrix Make sure you are using the corrsponding version. For example:


    "@microsoft/applicationinsights-react-js": "17.2.0",
    "@microsoft/applicationinsights-web": "3.2.0",

I'm aware of this, it's a bit of an issue when trying to use the most recent releases, e.g. "@microsoft/applicationinsights-offlinechannel-js": "0.2.2" with web 3.2.0. Or similarly "@microsoft/applicationinsights-web": "3.2.2" with "@microsoft/applicationinsights-react-js": "17.2.0".

, since docs say A post or sender channel is required for processing online events. Not quite clear to me whether I need to explicitly register/add this to the app insights instance?

To clarify:

1. If you only need to process online events, @microsoft/applicationinsights-web already includes a post channel, so no additional configuration is needed.

2. If your app will be offline for some time and you want to support telemetry being sent after it comes back online, you should include the offline-channel.

3. The note is informing users that for packages that do not include a send/post channel, the offline-channel cannot send telemetry on its own. It requires a post/send channel to perform that function.

Thanks for the additional information :)! So I'd assume above mentioned setup should work and the persisted data should have been send after setting offlineListener.setOnlineState(1).

MSNev commented 1 week ago

The current state of the versions with the Offline listener, AISKU and react-js is "messy", as part of the new release of the offline channel we had to make changes to the internal interfaces, while the latest offline "should" work with the 3.2.0 of the applicationinsights-web, it's not our recommended approach. You should use the offline channel that matches the version of the applicationinsights-web (AISKU). We believe that the issue with the react-js compile issues are due to older versions within the node_modules dependency chain -- clearing and updating all of the dependencies (especially for the react-js plugin) "should" fix the compile issue. Failing that the older react-js WILL work with 3.2.2, you will just need to workaround the TypeScript error by casting as "any" our using the "skipLibCheck" (At least that is the current understanding on how to avoid the TypeScript issue -- as mentioned they WILL run together).

p-hlp commented 1 week ago

@MSNev Appreciate the input regarding the ts issue.

Added a small demo repo here, where I was also playing around with inMemoMaxTime and maxSentBatchInterval. The behavior seems a bit different compared to when I tested before. The offline events are actually sent when going back online, however they're not sent in a batch, rather one at a time. So I assume I missed this before and it just looked like nothing was sent.

https://github.com/microsoft/ApplicationInsights-JS/assets/30762620/0aca0446-80bd-4e54-a63c-3d772b31e3f0

I'd appreciate any hints / clarifications whether this is the intended behavior or can/needs to be configured somewhere. None of the IOfflineChannelConfiguration properties sounded like they would increase the size of the batch that's sent.

MSNev commented 1 week ago

I'll let @Karlie-777 and @siyuniu-ms respond with any details from investigations etc. But for reference the Offline Channel was designed to store "batches" of events and when it comes back online it sends out these batches one at a time in a slow manner (as to not overload the network) and only "if" it detects that the normal online channel (Sender / Post) don't have anything waiting or are not current sending anything (ie. they are deemed idle -- again so we don't overload the network bandwidth).

So because it's designed for batches, when you are offline for an extended period of time the events "trickling" in will be automatically grouped into their own batches based on a bunch of stuff -- mostly time and total number (@Karlie-777 can elaborate more -- they should all have configuration options). So depending on the frequency of the events and these settings will determine the number of batches that get created and store (and then subsequently sent after coming back online).

The key goal (beyond just saving the events while offline) was to not overload the network bandwidth of not just the users machine but also any shared infrastructure (eg. a small company with 100 users who have been offline for several hours, when their internet connection comes back on we don't want to get sending errors (timeouts) because there is not network bandwidth by dumping 1000's of events the moment internet connection is detected and restored (by whatever mechanism is needed -- this is where the IOfflineListerner interface comes in)

p-hlp commented 4 days ago

Thanks for the in depth answer. That clears up quite a lot of things for me in regards to how the offline channel is supposed to work / be used.

@Karlie-777 & @siyuniu-ms please let me know If I can provide anything else to help with your investigations :).

Karlie-777 commented 4 days ago

do you mind trying adding some fields(for example isonline: false/true) to the events or name events as "offline"/"online" to mark events? and based on your inMemoMaxTime and maxSentBatchInterval configs, do you see offline events are sent out as expected? Thanks!