sentry-dotnet icon indicating copy to clipboard operation
sentry-dotnet copied to clipboard

Running several SentrySdk.CaptureMessage in parallel freezes the MAUI Android app

Open dalux-era opened this issue 1 month ago • 4 comments

Package

Sentry

.NET Flavor

.NET

.NET Version

9.0.203

OS

Android

OS Version

Android 15

Development Environment

Visual Studio v18.x

SDK Version

5.16.2

Self-Hosted Sentry Version

No response

Workload Versions

android 35.0.39/9.0.100 SDK 9.0.200, VS 17.13.35931.197 aspire 8.2.2/8.0.100 SDK 9.0.200, VS 17.13.35931.197 ios 18.2.9173/9.0.100 SDK 9.0.200, VS 17.13.35931.197 maccatalyst 18.2.9173/9.0.100 SDK 9.0.200, VS 17.13.35931.197 maui-windows 9.0.14/9.0.100 SDK 9.0.200, VS 17.13.35931.197

UseSentry or SentrySdk.Init call

.UseSentry("")

Steps to Reproduce

  1. Run SentrySdk.CaptureMessage("Hello") in parallel
  2. Use this somewhere in Main thread, like on a button press
 Parallel.Invoke(
     () => SentrySdk.CaptureMessage("Hello"),
     () => SentrySdk.CaptureMessage("Hello"),
     () => SentrySdk.CaptureMessage("Hello"),
     () => SentrySdk.CaptureMessage("Hello"),
     () => SentrySdk.CaptureMessage("Hello")
	);

Expected Result

5 Messages will be reported to Sentry

Actual Result

App freezes and stops responding. This seems like a regression as at least the Sentry.Maui 5.4.0 version works fine with the same code. Please reach out if a sample is needed

dalux-era avatar Dec 09 '25 09:12 dalux-era

NET-549

linear[bot] avatar Dec 09 '25 09:12 linear[bot]

@dalux-era I'm not able to reproduce this. I tried creating a brand new maui app with this:

	private void OnCounterClicked(object? sender, EventArgs e)
	{
		count++;

		if (count == 1)
			CounterBtn.Text = $"Clicked {count} time";
		else
			CounterBtn.Text = $"Clicked {count} times";

		Parallel.Invoke(
			() => SentrySdk.CaptureMessage("Hello"),
			() => SentrySdk.CaptureMessage("Hello"),
			() => SentrySdk.CaptureMessage("Hello"),
			() => SentrySdk.CaptureMessage("Hello"),
			() => SentrySdk.CaptureMessage("Hello")
		);
		
		SemanticScreenReader.Announce(CounterBtn.Text);
	}

The app runs without issue.

Image

I tried using both dotnet SDK 9.0.203 and 9.0.308 (the most recent 9.x release).

jamescrosswell avatar Dec 10 '25 01:12 jamescrosswell

Can you try running the same app in release configuration? It might be related to that. @jamescrosswell I tried running the same code you show in release and I could reproduce the bug

dalux-era avatar Dec 10 '25 06:12 dalux-era

OK, in release mode I can reproduce this. Thanks @dalux-era - we'll look into it.

jamescrosswell avatar Dec 10 '25 21:12 jamescrosswell

This one is a headscratcher... I added a bunch of logging to work out where it's coming from and I think it's coming from somewhere in this method: https://github.com/getsentry/sentry-dotnet/blob/876ec162482860676ff095e254187ebf7f6cd9bc/src/Sentry.Android.AssemblyReader/V2/AssemblyStoreReader.cs#L51-L76

That stacks up with the fact that only became an issue in the 5.5.0 release (which is when we introduced the v2 assembly readers).

However if I add further logging inside that method to try to determine more precisely which line is causing this, the problem goes away (even if I bump the number of parallel executions to 100 rather than 5). And sometimes when I add logging nowhere near that method, it goes away. Presumably the logging impacts the execution timings enough that whatever contention is causing the blocking is no longer an issue.

@dalux-era as a temporary workaround, I think you can set SentryOptions.AttachStacktrace = false when initialising Sentry... this seems to avoid the issue for me. If that setting is true, Sentry creates and attaches a stack trace even for events that don't have them by default (like CaptureMessage events). If it's false, you only get stack traces for things like exceptions.

It's worth pointing out that creating a stack trace is a really expensive operation. If you're planning on calling CreateMessage in a tight loop or in parallel like this, you probably want to disable this setting anyway, since it will really slow your app down (even once we resolve the issue with the hanging).

jamescrosswell avatar Dec 16 '25 02:12 jamescrosswell

Ahhh, I think I might see an obvious issue actually. The store reader gets assigned to the options (a singleton) on startup... and this isn't really thread safe. If/when multiple threads are using this, they're all sharing the same StoreStream.

That's embarrassing, since I'm on the blame for that commit/code. I vendored it in from Microsoft... but clearly not carefully enough.

jamescrosswell avatar Dec 16 '25 03:12 jamescrosswell

Thanks for looking into it @jamescrosswell ! Just an addition to the original ticket. The reproduction sample is just oversimplified version of the actual scenario. In our code, the app would freeze when 2 SentrySdk.CaptureException would be executed at the same time due to different event subscriptions. As you found out it seems like a thread so fingers crossed that this will also be fixed by you making operations threads-safe 💯

dalux-era avatar Dec 16 '25 07:12 dalux-era