diff --git a/AccessQueueService/Data/TakeANumberAccessQueueRepo.cs b/AccessQueueService/Data/TakeANumberAccessQueueRepo.cs index 184b512..e7dbafa 100644 --- a/AccessQueueService/Data/TakeANumberAccessQueueRepo.cs +++ b/AccessQueueService/Data/TakeANumberAccessQueueRepo.cs @@ -61,28 +61,27 @@ namespace AccessQueueService.Data return count; } - public bool DidDequeueUntilFull(AccessQueueConfig config) + private bool HasValidActiveUsersCache(AccessQueueConfig config, DateTime now) + { + return config.CacheMilliseconds.HasValue && _cachedActiveUsers.HasValue && (now - _cachedActiveUsersTime).TotalMilliseconds < config.CacheMilliseconds.Value; + } + + private int GetOpenSpots(AccessQueueConfig config, int activeUsers) + { + return config.CapacityLimit.Value - activeUsers; + } + + private int UpdateActiveUsersCache(DateTime now, DateTime activeCutoff) { - var now = DateTime.UtcNow; - var activeCutoff = now.AddSeconds(-config.ActivitySeconds.Value); - if (config.CacheMilliseconds.HasValue && _cachedActiveUsers.HasValue && (now - _cachedActiveUsersTime).TotalMilliseconds < config.CacheMilliseconds) - { - var numberOfActiveUsers = _cachedActiveUsers.Value; - var openSpots = config.CapacityLimit - numberOfActiveUsers; - if (openSpots <= 0) - { - return true; - } - } _cachedActiveUsers = _accessTickets.Count(t => t.Value.ExpiresOn > now && t.Value.LastActive > activeCutoff); _cachedActiveUsersTime = now; - var openSpotsNew = config.CapacityLimit - _cachedActiveUsers; - if (openSpotsNew <= 0) - { - return true; - } + return _cachedActiveUsers.GetValueOrDefault(); + } + + private int DequeueUsersUntilFull(int openSpots, DateTime now, DateTime activeCutoff, AccessQueueConfig config) + { int filledSpots = 0; - while (filledSpots < openSpotsNew && _nowServing < _nextUnusedTicket) + while (filledSpots < openSpots && _nowServing < _nextUnusedTicket) { if (_accessQueue.TryRemove(_nowServing++, out var nextUser)) { @@ -95,19 +94,49 @@ namespace AccessQueueService.Data _accessTickets[nextUser.UserId] = new AccessTicket { UserId = nextUser.UserId, - ExpiresOn = now.AddSeconds(config.ExpirationSeconds.Value), + ExpiresOn = now.AddSeconds(config.ExpirationSeconds ?? 0), LastActive = now }; filledSpots++; } } + return filledSpots; + } + + public bool DidDequeueUntilFull(AccessQueueConfig config) + { + var now = DateTime.UtcNow; + if (!config.ActivitySeconds.HasValue || !config.ExpirationSeconds.HasValue || !config.CapacityLimit.HasValue) + { + throw new Exception("Required config values are not defined."); + } + var activeCutoff = now.AddSeconds(-config.ActivitySeconds.Value); + + int activeUsers; + if (HasValidActiveUsersCache(config, now)) + { + activeUsers = _cachedActiveUsers.GetValueOrDefault(); + } + else + { + activeUsers = UpdateActiveUsersCache(now, activeCutoff); + } + + var openSpots = GetOpenSpots(config, activeUsers); + if (openSpots <= 0) + { + return true; + } + + int filledSpots = DequeueUsersUntilFull(openSpots, now, activeCutoff, config); + // Invalidate cache if any users were granted access if (filledSpots > 0) { _cachedActiveUsers = null; _cachedActiveUsersTime = DateTime.MinValue; } - return filledSpots == openSpotsNew; + return filledSpots == openSpots; } public AccessTicket? GetTicket(string userId)