Skip to content

Replay is making my Angular app super slow #6946

Closed

Description

@mebibou

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which package are you using?

@sentry/angular

SDK Version

7.31.1

Framework Version

Angular 14.2.8

Link to Sentry event

No response

SDK Setup

Sentry.init({
  ...environment.sentryApi,
  replaysSessionSampleRate: 0.5,
  replaysOnErrorSampleRate: 1.0,
  integrations: [
    new Sentry.Replay(),
    new Sentry.Integrations.TryCatch({
      XMLHttpRequest: false
    }),
    new BrowserTracing({
      tracingOrigins: ['apiUrl']
    })
  ],
  tracesSampleRate: 0.5
});

Steps to Reproduce

Add the Replay integration to the Angular app. Without it the website is smooth, as soon as I add it it gets super slow continuously

Expected Result

Add Replay shouldn't impact performance so much, or it's basically becomes unusable

Actual Result

Everything is slow

Activity

  1. Lms24 commented on Jan 26, 2023

    @Lms24
    Member

    Hi @mebibou, thanks for writing in! I'm afraid, Replay is always going to add overhead to your app, as rrweb (the underlying library we use to record everything that's happening) just needs to listen and react to so many events, DOM mutations, style changes, etc.

    We're right now working on performance overhead measurements, to better understand the overall impact. For instance, #6611 introduced the first version of them. We're still trying to improve here, as we've noticed that results seem to fluctuate and depend a lot on the individual apps.

    It's interesting that the impact is so noticeable in your app. Would you mind sharing a little information about it? For instance:

    • Do you have a lot of frequent DOM mutations? Or a bunch of animations?
    • How do users interact with your app? E.g. a lot of input/clicking vs. more reading
    • How complex is your app? For instance, in terms of number of components or bundle size
    • Any chance that you're running into very frequent (maybe unintentional) component updates? We've observerd that high-frequency DOM updates have significant impact on Replay playback performance. My assumption is that the same thing holds true for recording.
    • Did you perform any measurements? e.g. in terms of CPU or web vitals (e.g. LCP) difference of your plain app vs. your app with Replay recording?

    Lastly, I guess the thin you can try at the moment to mitigate the overhead would be to lower the sample rates of errors and sessions. If a session is not sampled (both entire sessions and errors), our integration doesn't do anything and there should be no noticable performance impact.

    Hope this helps a little. LMK if you have more questions :)

  2. mebibou commented on Jan 26, 2023

    @mebibou
    Author

    @Lms24 thanks for the reply

    Our app does have a lot of interaction, and one part of it where the lag is very noticeable is a place where we have a dynamic form, i.e. the user can add more components, add some text, sometimes clicking on a button will open a dialogue, etc. so based on ReactiveForms.

    But even on simple pages where we just display a list of search results, the results took about 2-5 seconds to display compared to without the Replay you would barely see the loader.

    I didn't really perform any measurements as users started to complain the website was too slow to use so I simply disabled it. I don't think sampling would help, as it would still fall randomly on some users to have a horrible experience?

    An idea that I had though: is there any way to enable the integration, but have some way to turn it on/off at runtime? I am thinking in cases where the user has a bug, and it could "turn on recording" (with a disclaimer that everything will be slower when recording is on)?

  3. Lms24 commented on Jan 26, 2023

    @Lms24
    Member

    Our app does have a lot of interaction, and one part of it where the lag is very noticeable is a place where we have a dynamic form, i.e. the user can add more components, add some text, sometimes clicking on a button will open a dialogue, etc. so based on ReactiveForms.

    A wild guess here would be that maybe some validation logic is constantly updating the UI after an input? It's been a while since I played with Angular Reactive Forms but maybe the debounceTime operator for observing user input helps?

    An idea that I had though: is there any way to enable the integration, but have some way to turn it on/off at runtime? I am thinking in cases where the user has a bug, and it could "turn on recording" (with a disclaimer that everything will be slower when recording is on)?

    Yes, you can start and stop recording manually. For instance, it might be possible to stop recording on these more complex pages.

    Furthermore, only recording when errors happen is supported ootb by the Replay integration:

      replaysSessionSampleRate: 0,
      replaysOnErrorSampleRate: 1.0, // or a smaller value, depending on what you perefer:

    Note though, at the beginning of a session, we make a sampling decision based on the sample rates. If the session is sampled for errors, we'll still record all the time but only keep the last 60s of recording in the buffer. Hence, performance degredation is probably still noticeable.

  4. mebibou commented on Jan 26, 2023

    @mebibou
    Author

    sorry missed that section in the readme, I will have a play with it when I can spend more time on this.

    For instance, it might be possible to stop recording on these more complex pages.

    Yes but unfortunately, the more complex the page, the more the need to record the sessions!

    We do use debounceTime and other performance related tricks, but when you've got hundreds of inputs and buttons etc on a page, eventually the memory usage increases. I imagined this would impact performances, but not by that much (most of the time the page was unresponsive after a few minutes)

  5. billyvg commented on Jan 26, 2023

    @billyvg
    Member

    @mebibou do you have a publicly accessible URL where this happens that we can use to test ourselves? I'm curious if it's form input related and if ignoring events on the inputs would help perf.

  6. Lms24 commented on Jan 26, 2023

    @Lms24
    Member

    One more question: What kind of change detection strategy are you using?

  7. woodchuck commented on Jan 31, 2023

    @woodchuck

    We use Angular Material. In a tab group you can wrap a tab with matTabContent to prevent it from initializing until you actually click on the tab. For tabs where we've done that, it appears Sentry replay causes it to hang badly. For example, the initial Audits tab here loads fine, clicking to Pending MR Review works fine, but clicking Incomplete/Approval needed hangs to the point the app is unusable. This worked fine before enabling replay, and adding/removing matTabContent toggles the problem on and off.

    <mat-tab-group (selectedTabChange)="onTabChanged($event);">
      <mat-tab label="Audits">
        <app-audit-list [dateRange]=dateRange></app-audit-list>
      </mat-tab>
      <mat-tab label="Pending MR Review">
          <app-result-list [data]="mrPending"></app-result-list>
      </mat-tab>
      <mat-tab label="Incomplete/Approval Needed">
        <ng-template matTabContent>
          <app-result-list [data]="mrIncomplete"></app-result-list>
        </ng-template>
      </mat-tab>
    </mat-tab-group>
    

    We are using the default change detection strategy.

    I'd also like to say replay is amazing. It's been a long time since software has delighted me this much. Kudos!

  8. mebibou commented on Jan 31, 2023

    @mebibou
    Author

    One more question: What kind of change detection strategy are you using?

    We use the default in most places. We tried to use "OnPush" but we had many problems with components no re-rendering anything and as the application is quite complex, it would take too long to debug/rewrite everything so OnPush is applicable.
    Is that something that doesn't bode well with Replay?

  9. 70 remaining items

  10. mydea commented on Jan 4, 2024

    @mydea
    Member

    I opened a PR to hopefully fix this on rrweb side: getsentry/rrweb#150

  11. duncan-c commented on Jan 5, 2024

    @duncan-c

    Great work with the fix @mydea!

    Sorry I didn't reply in time. The way I disabled it was to globally disable the monkey-patching of the function by Angular, because we didn't need change detection to automatically run whenever RAF runs - but obviously that's not a feasible solution for many people.

    The iframe technique is clever, and will also mean that it'll work for other libraries that override the native implementation 💪

    Sadly the performance is still not great on our application, but I did realise that we were using an outdated version of the JS SDK because we use the Capacitor plugin which is locked to v7.81 - and when I manually overrode this to get the latest version things did improve a bit, because of the rrweb improvements.
    We're seeing a lot of mutation limit warnings in the breadcrumbs - so I guess the main issue is that Angular is pretty heavy on the dom mutations, unless you're really careful with change detection, etc.

  12. moved this to Waiting for: Product Owner in GitHub Issues with 👀 2on Jan 5, 2024
  13. mydea commented on Jan 5, 2024

    @mydea
    Member

    Thanks for the info! yeah, updating to a more recent version of replay should improve performance a bit. we will work on further improvements down the line too! But it will be great to unblock this angular specific issue here 🙏

  14. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 2on Jan 5, 2024
  15. AbhiPrasad commented on Jan 10, 2024

    @AbhiPrasad
    Contributor

    The fix for this was released with https://github.com/getsentry/sentry-javascript/releases/tag/7.93.0 - please give it a try!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions