From 1c1690e804f3b59e33c37444975000f66939b6c1 Mon Sep 17 00:00:00 2001 From: arturovt Date: Fri, 5 Jul 2024 17:19:22 +0300 Subject: [PATCH] fix(angular): remove `afterSendEvent` listener once root injector is destroyed In this commit, we added cleanup logic to handle the removal of `afterSendEvent`, which is set up within the Angular error handler. This fixes memory leaks that occur when the event is still being handled after the root view is removed. --- packages/angular/src/errorhandler.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/angular/src/errorhandler.ts b/packages/angular/src/errorhandler.ts index 4ea44c2ffc63..dfca12bb6b43 100644 --- a/packages/angular/src/errorhandler.ts +++ b/packages/angular/src/errorhandler.ts @@ -1,5 +1,5 @@ import { HttpErrorResponse } from '@angular/common/http'; -import type { ErrorHandler as AngularErrorHandler } from '@angular/core'; +import type { ErrorHandler as AngularErrorHandler, OnDestroy } from '@angular/core'; import { Inject, Injectable } from '@angular/core'; import * as Sentry from '@sentry/browser'; import type { ReportDialogOptions } from '@sentry/browser'; @@ -80,12 +80,14 @@ function isErrorOrErrorLikeObject(value: unknown): value is Error { * Implementation of Angular's ErrorHandler provider that can be used as a drop-in replacement for the stock one. */ @Injectable({ providedIn: 'root' }) -class SentryErrorHandler implements AngularErrorHandler { +class SentryErrorHandler implements AngularErrorHandler, OnDestroy { protected readonly _options: ErrorHandlerOptions; /* indicates if we already registered our the afterSendEvent handler */ private _registeredAfterSendEventHandler; + private _removeAfterSendEventListener: VoidFunction | null = null; + public constructor(@Inject('errorHandlerOptions') options?: ErrorHandlerOptions) { this._registeredAfterSendEventHandler = false; @@ -95,6 +97,12 @@ class SentryErrorHandler implements AngularErrorHandler { }; } + public ngOnDestroy(): void { + if (this._removeAfterSendEventListener) { + this._removeAfterSendEventListener(); + } + } + /** * Method called for every value captured through the ErrorHandler */ @@ -119,7 +127,7 @@ class SentryErrorHandler implements AngularErrorHandler { const client = Sentry.getClient(); if (client && !this._registeredAfterSendEventHandler) { - client.on('afterSendEvent', (event: Event) => { + this._removeAfterSendEventListener = client.on('afterSendEvent', (event: Event) => { if (!event.type && event.event_id) { runOutsideAngular(() => { Sentry.showReportDialog({ ...this._options.dialogOptions, eventId: event.event_id! });