Skip to content

Commit 9521bd1

Browse files
fix: Remove AppDomain.CurrentDomain.ProcessExit hook on shutdown (#4323)
Resolves #3141 - #3141
1 parent 9503d83 commit 9521bd1

File tree

4 files changed

+119
-1
lines changed

4 files changed

+119
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- Custom ISentryEventProcessors are now run for native iOS events ([#4318](https://github.com/getsentry/sentry-dotnet/pull/4318))
1717
- Crontab validation when capturing checkins ([#4314](https://github.com/getsentry/sentry-dotnet/pull/4314))
1818
- Native AOT: link to static `lzma` on Linux/MUSL ([#4326](https://github.com/getsentry/sentry-dotnet/pull/4326))
19+
- AppDomain.CurrentDomain.ProcessExit hook is now removed on shutdown ([#4323](https://github.com/getsentry/sentry-dotnet/pull/4323))
1920

2021
### Dependencies
2122

src/Sentry/Integrations/AppDomainProcessExitIntegration.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Sentry.Integrations;
55

6-
internal class AppDomainProcessExitIntegration : ISdkIntegration
6+
internal class AppDomainProcessExitIntegration : ISdkIntegration, IDisposable
77
{
88
private readonly IAppDomain _appDomain;
99
private IHub? _hub;
@@ -24,4 +24,9 @@ internal void HandleProcessExit(object? sender, EventArgs e)
2424
_options?.LogInfo("AppDomain process exited: Disposing SDK.");
2525
(_hub as IDisposable)?.Dispose();
2626
}
27+
28+
public void Dispose()
29+
{
30+
_appDomain.ProcessExit -= HandleProcessExit;
31+
}
2732
}

src/Sentry/Internal/Hub.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Sentry.Extensibility;
22
using Sentry.Infrastructure;
3+
using Sentry.Integrations;
34
using Sentry.Protocol.Envelopes;
45
using Sentry.Protocol.Metrics;
56

@@ -14,6 +15,7 @@ internal class Hub : IHub, IDisposable
1415
private readonly SentryOptions _options;
1516
private readonly RandomValuesFactory _randomValuesFactory;
1617
private readonly IReplaySession _replaySession;
18+
private readonly List<IDisposable> _integrationsToCleanup = new();
1719

1820
#if MEMORY_DUMP_SUPPORTED
1921
private readonly MemoryMonitor? _memoryMonitor;
@@ -84,6 +86,10 @@ internal Hub(
8486
{
8587
options.LogDebug("Registering integration: '{0}'.", integration.GetType().Name);
8688
integration.Register(this, options);
89+
if (integration is IDisposable disposableIntegration)
90+
{
91+
_integrationsToCleanup.Add(disposableIntegration);
92+
}
8793
}
8894
}
8995

@@ -772,6 +778,18 @@ public void Dispose()
772778
return;
773779
}
774780

781+
foreach (var integration in _integrationsToCleanup)
782+
{
783+
try
784+
{
785+
integration.Dispose();
786+
}
787+
catch (Exception e)
788+
{
789+
_options.LogError("Failed to dispose integration {0}: {1}", integration.GetType().Name, e);
790+
}
791+
}
792+
775793
#if MEMORY_DUMP_SUPPORTED
776794
_memoryMonitor?.Dispose();
777795
#endif

test/Sentry.Tests/HubTests.cs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,6 +1988,100 @@ public void CaptureUserFeedback_InvalidEmail_FeedbackDropped(string email)
19881988
_fixture.Client.Received(1).CaptureUserFeedback(Arg.Is<UserFeedback>(f => f.Email.IsNull()));
19891989
#pragma warning restore CS0618 // Type or member is obsolete
19901990
}
1991+
1992+
private class TestDisposableIntegration : ISdkIntegration, IDisposable
1993+
{
1994+
public int Registered { get; private set; }
1995+
public int Disposed { get; private set; }
1996+
1997+
public void Register(IHub hub, SentryOptions options)
1998+
{
1999+
Registered++;
2000+
}
2001+
2002+
protected virtual void Cleanup()
2003+
{
2004+
Disposed++;
2005+
}
2006+
2007+
public void Dispose()
2008+
{
2009+
Cleanup();
2010+
}
2011+
}
2012+
2013+
private class TestFlakyDisposableIntegration : TestDisposableIntegration
2014+
{
2015+
protected override void Cleanup()
2016+
{
2017+
throw new InvalidOperationException("Cleanup failed");
2018+
}
2019+
}
2020+
2021+
[Fact]
2022+
public void Dispose_IntegrationsWithCleanup_CleanupCalled()
2023+
{
2024+
// Arrange
2025+
var integration1 = new TestDisposableIntegration();
2026+
var integration2 = Substitute.For<ISdkIntegration>();
2027+
var integration3 = new TestDisposableIntegration();
2028+
_fixture.Options.AddIntegration(integration1);
2029+
_fixture.Options.AddIntegration(integration2);
2030+
_fixture.Options.AddIntegration(integration3);
2031+
var hub = _fixture.GetSut();
2032+
2033+
// Act
2034+
hub.Dispose();
2035+
2036+
// Assert
2037+
integration1.Disposed.Should().Be(1);
2038+
integration3.Disposed.Should().Be(1);
2039+
}
2040+
2041+
[Fact]
2042+
public void Dispose_CleanupThrowsException_ExceptionHandledAndLogged()
2043+
{
2044+
// Arrange
2045+
var integration1 = new TestDisposableIntegration();
2046+
var integration2 = new TestFlakyDisposableIntegration();
2047+
var integration3 = new TestDisposableIntegration();
2048+
_fixture.Options.AddIntegration(integration1);
2049+
_fixture.Options.AddIntegration(integration2);
2050+
_fixture.Options.AddIntegration(integration3);
2051+
_fixture.Options.Debug = true;
2052+
_fixture.Options.DiagnosticLogger = Substitute.For<IDiagnosticLogger>();
2053+
_fixture.Options.DiagnosticLogger!.IsEnabled(Arg.Any<SentryLevel>()).Returns(true);
2054+
var hub = _fixture.GetSut();
2055+
2056+
// Act
2057+
hub.Dispose();
2058+
2059+
// Assert
2060+
integration1.Disposed.Should().Be(1);
2061+
integration2.Disposed.Should().Be(0);
2062+
integration3.Disposed.Should().Be(1);
2063+
_fixture.Options.DiagnosticLogger.Received(1).Log(
2064+
SentryLevel.Error,
2065+
Arg.Is<string>(s => s.Contains("Failed to dispose integration")),
2066+
Arg.Any<InvalidOperationException>(),
2067+
Arg.Any<object[]>());
2068+
}
2069+
2070+
[Fact]
2071+
public void Dispose_CalledMultipleTimes_CleanupCalledOnlyOnce()
2072+
{
2073+
// Arrange
2074+
var integration = new TestDisposableIntegration();
2075+
_fixture.Options.AddIntegration(integration);
2076+
var hub = _fixture.GetSut();
2077+
2078+
// Act
2079+
hub.Dispose();
2080+
hub.Dispose();
2081+
2082+
// Assert
2083+
integration.Disposed.Should().Be(1);
2084+
}
19912085
}
19922086

19932087
#if NET6_0_OR_GREATER

0 commit comments

Comments
 (0)