diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs index e7b2d151c..ca50d4c2b 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs @@ -13,6 +13,7 @@ namespace MediaBrowser.Providers.TV { private static volatile TvDbClientManager instance; // TODO add to DI once Bond's PR is merged + private readonly SemaphoreSlim _cacheWriteLock = new SemaphoreSlim(1, 1); private static MemoryCache _cache; private static readonly object syncRoot = new object(); private static TvDbClient tvDbClient; @@ -73,24 +74,32 @@ namespace MediaBrowser.Providers.TV public async Task GetSeriesByName(string name, CancellationToken cancellationToken) { - if (_cache.TryGetValue(name, out SeriesSearchResult[] series)) - { - return series; - } - var result = await TvDbClient.Search.SearchSeriesByNameAsync(name, cancellationToken); - _cache.Set(name, result.Data, DateTimeOffset.UtcNow.AddHours(1)); - return result.Data; + return await TryGetValue(name, + async () => (await TvDbClient.Search.SearchSeriesByNameAsync(name, cancellationToken)).Data); } public async Task GetSeriesById(int tvdbId, CancellationToken cancellationToken) { - if (_cache.TryGetValue(tvdbId, out Series series)) + return await TryGetValue(tvdbId, + async () => (await TvDbClient.Series.GetAsync(tvdbId, cancellationToken)).Data); + } + + private async Task TryGetValue(object key, Func> resultFactory) + { + if (_cache.TryGetValue(key, out T cachedValue)) { - return series; + return cachedValue; + } + using (_cacheWriteLock) + { + if (_cache.TryGetValue(key, out cachedValue)) + { + return cachedValue; + } + var result = await resultFactory.Invoke(); + _cache.Set(key, result, DateTimeOffset.UtcNow.AddHours(1)); + return result; } - var result = await TvDbClient.Series.GetAsync(tvdbId, cancellationToken); - _cache.Set(tvdbId, result.Data, DateTimeOffset.UtcNow.AddHours(1)); - return result.Data; } } }