sportradar / UnifiedOddsSdkNetCore

UnifiedFeed SDK is a client library that enables easier integration with the Betradar XML feeds. SDK exposes XML feed service interface in a more user-friendly way and isolates the client from having to do XML feed parsing, proper connection handling, error recovery, event queuing, data caching and dispatching.
https://sportradar.github.io/UnifiedOddsSdkNetCore/
Other
17 stars 14 forks source link

Thread deadlocking in Competitor profile due to Task.Run().Wait() #28

Closed mhbuck closed 1 year ago

mhbuck commented 1 year ago

Upgrading to version 1.30.x there was a noticed issue with threads locking specifically on start up of services connecting to the Betradar Feed. It was also noticed during recovery and at peak times. This has been noticed in both the integration and production environments.

This is was initially seen by looking at the threadpool queue length image

Investigations were done by running dot trace and pointing to the Task.Wait in the LoadProfileInCache (Code - https://github.com/sportradar/UnifiedOddsSdkNetCore/blob/master/src/Sportradar.OddsFeed.SDK/Entities/REST/Internal/EntitiesImpl/Competitor.cs#L511)

image The dtt file can be made available if needed.

The problem with the code is that doing Task.Run().Wait() will wait on the thread for the response and deadlock that thread. This problem is explained in depth in this blog post https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

The current thinking is that this issue has been around for a while but the change to increase the SemaphorePool count to 500 has contributed to this problem being more visible https://github.com/sportradar/UnifiedOddsSdkNetCore/blob/c898704f8d6d15365f335ea35db0ef2df477a325/src/Sportradar.OddsFeed.SDK/API/Internal/UnityFeedBootstrapper.cs#L275

The code in the PR has been running in our production environment for approximately two weeks and we have noticed an improvement and have no thread queuing issues.

Exposing EnsureProfileLoaded() on ICompetitor allows the users to opt into loading a profile into cache using await and not having to incur the thread deadlock when trying to get data from the various properties on the ICompetitor interface which in the implementation calls LoadCompetitorProfileInCache which deadlocks. This is something currently being used in production.

There is also the the potential to apply a similar approach for FetchEventCompetitorsVirtual which suffers from the same thread locking problem.

Please note that I originally raised this through the SportRadar support process which I have not had a technical response since it was reported. The internal ticket number is Ticket#857483. For any further details or any other questions specific to our integration we would be happy to get onto a call about this.