Cache manageent for bussines units

This commit is contained in:
Duncan Tourolle 2026-06-27 09:34:07 +02:00
parent fef1bd6b17
commit 5667c2e12f

View File

@ -18,8 +18,10 @@ public class CategoryService : ICategoryService
private readonly ILogger<CategoryService> _logger; private readonly ILogger<CategoryService> _logger;
private readonly ISRFApiClientFactory _apiClientFactory; private readonly ISRFApiClientFactory _apiClientFactory;
private readonly TimeSpan _topicsCacheDuration = TimeSpan.FromHours(24); private readonly TimeSpan _topicsCacheDuration = TimeSpan.FromHours(24);
private Dictionary<string, PlayV3Topic>? _topicsCache;
private DateTime _topicsCacheExpiry = DateTime.MinValue; // Cache topics per business unit. A single shared cache would return one unit's
// topics (e.g. German SRF) even after the user switched to another (e.g. French RTS).
private readonly Dictionary<string, (Dictionary<string, PlayV3Topic> Topics, DateTime Expiry)> _topicsCacheByUnit = new(StringComparer.OrdinalIgnoreCase);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CategoryService"/> class. /// Initializes a new instance of the <see cref="CategoryService"/> class.
@ -35,11 +37,11 @@ public class CategoryService : ICategoryService
/// <inheritdoc /> /// <inheritdoc />
public async Task<List<PlayV3Topic>> GetTopicsAsync(string businessUnit, CancellationToken cancellationToken = default) public async Task<List<PlayV3Topic>> GetTopicsAsync(string businessUnit, CancellationToken cancellationToken = default)
{ {
// Return cached topics if still valid // Return cached topics for this business unit if still valid
if (_topicsCache != null && DateTime.UtcNow < _topicsCacheExpiry) if (_topicsCacheByUnit.TryGetValue(businessUnit, out var cached) && DateTime.UtcNow < cached.Expiry)
{ {
_logger.LogDebug("Returning cached topics for business unit: {BusinessUnit}", businessUnit); _logger.LogDebug("Returning cached topics for business unit: {BusinessUnit}", businessUnit);
return _topicsCache.Values.ToList(); return cached.Topics.Values.ToList();
} }
_logger.LogInformation("Fetching topics for business unit: {BusinessUnit}", businessUnit); _logger.LogInformation("Fetching topics for business unit: {BusinessUnit}", businessUnit);
@ -48,13 +50,13 @@ public class CategoryService : ICategoryService
if (topics != null && topics.Count > 0) if (topics != null && topics.Count > 0)
{ {
// Cache topics by ID for quick lookups // Cache topics by ID for quick lookups, scoped to this business unit
_topicsCache = topics var byId = topics
.Where(t => !string.IsNullOrEmpty(t.Id)) .Where(t => !string.IsNullOrEmpty(t.Id))
.ToDictionary(t => t.Id!, t => t); .ToDictionary(t => t.Id!, t => t);
_topicsCacheExpiry = DateTime.UtcNow.Add(_topicsCacheDuration); _topicsCacheByUnit[businessUnit] = (byId, DateTime.UtcNow.Add(_topicsCacheDuration));
_logger.LogInformation("Cached {Count} topics for business unit: {BusinessUnit}", _topicsCache.Count, businessUnit); _logger.LogInformation("Cached {Count} topics for business unit: {BusinessUnit}", byId.Count, businessUnit);
} }
return topics ?? new List<PlayV3Topic>(); return topics ?? new List<PlayV3Topic>();
@ -63,13 +65,14 @@ public class CategoryService : ICategoryService
/// <inheritdoc /> /// <inheritdoc />
public async Task<PlayV3Topic?> GetTopicByIdAsync(string topicId, string businessUnit, CancellationToken cancellationToken = default) public async Task<PlayV3Topic?> GetTopicByIdAsync(string topicId, string businessUnit, CancellationToken cancellationToken = default)
{ {
// Ensure topics are loaded // Ensure topics are loaded for this business unit
if (_topicsCache == null || DateTime.UtcNow >= _topicsCacheExpiry) if (!_topicsCacheByUnit.TryGetValue(businessUnit, out var cached) || DateTime.UtcNow >= cached.Expiry)
{ {
await GetTopicsAsync(businessUnit, cancellationToken).ConfigureAwait(false); await GetTopicsAsync(businessUnit, cancellationToken).ConfigureAwait(false);
_topicsCacheByUnit.TryGetValue(businessUnit, out cached);
} }
return _topicsCache?.GetValueOrDefault(topicId); return cached.Topics?.GetValueOrDefault(topicId);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -101,8 +104,7 @@ public class CategoryService : ICategoryService
/// <inheritdoc /> /// <inheritdoc />
public void ClearCache() public void ClearCache()
{ {
_topicsCache = null; _topicsCacheByUnit.Clear();
_topicsCacheExpiry = DateTime.MinValue;
_logger.LogInformation("Topics cache cleared"); _logger.LogInformation("Topics cache cleared");
} }