add caching for performance
This commit is contained in:
parent
a4ab44faf9
commit
f3f599c5df
|
@ -16,6 +16,6 @@ namespace AccessQueueService.Data
|
||||||
public void Enqueue(AccessTicket ticket);
|
public void Enqueue(AccessTicket ticket);
|
||||||
public int DeleteExpiredTickets();
|
public int DeleteExpiredTickets();
|
||||||
public bool RemoveUser(string userId);
|
public bool RemoveUser(string userId);
|
||||||
public bool DidDequeueUntilFull(int activeSeconds, int expirationSeconds, int capacityLimit);
|
public bool DidDequeueUntilFull(AccessQueueConfig config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@ namespace AccessQueueService.Data
|
||||||
internal ulong _nowServing = 0;
|
internal ulong _nowServing = 0;
|
||||||
internal ulong _nextUnusedTicket = 0;
|
internal ulong _nextUnusedTicket = 0;
|
||||||
|
|
||||||
|
private int? _cachedActiveUsers = null;
|
||||||
|
private DateTime _cachedActiveUsersTime = DateTime.MinValue;
|
||||||
|
|
||||||
public int GetUnexpiredTicketsCount() => _accessTickets.Count(t => t.Value.ExpiresOn > DateTime.UtcNow);
|
public int GetUnexpiredTicketsCount() => _accessTickets.Count(t => t.Value.ExpiresOn > DateTime.UtcNow);
|
||||||
public int GetActiveTicketsCount(DateTime activeCutoff) => _accessTickets
|
public int GetActiveTicketsCount(DateTime activeCutoff) => _accessTickets
|
||||||
.Count(t => t.Value.ExpiresOn > DateTime.UtcNow && t.Value.LastActive > activeCutoff);
|
.Count(t => t.Value.ExpiresOn > DateTime.UtcNow && t.Value.LastActive > activeCutoff);
|
||||||
|
@ -58,39 +61,53 @@ namespace AccessQueueService.Data
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DidDequeueUntilFull(int activeSeconds, int expirationSeconds, int capacityLimit)
|
public bool DidDequeueUntilFull(AccessQueueConfig config)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var activeCutoff = now.AddSeconds(-activeSeconds);
|
var activeCutoff = now.AddSeconds(-config.ActivitySeconds.Value);
|
||||||
var numberOfActiveUsers = _accessTickets.Count(t => t.Value.ExpiresOn > now && t.Value.LastActive > activeCutoff);
|
if (config.CacheMilliseconds.HasValue && _cachedActiveUsers.HasValue && (now - _cachedActiveUsersTime).TotalMilliseconds < config.CacheMilliseconds)
|
||||||
var openSpots = capacityLimit - numberOfActiveUsers;
|
{
|
||||||
|
var numberOfActiveUsers = _cachedActiveUsers.Value;
|
||||||
|
var openSpots = config.CapacityLimit - numberOfActiveUsers;
|
||||||
if (openSpots <= 0)
|
if (openSpots <= 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int filledSpots = 0;
|
}
|
||||||
while (filledSpots < openSpots && _nowServing < _nextUnusedTicket)
|
_cachedActiveUsers = _accessTickets.Count(t => t.Value.ExpiresOn > now && t.Value.LastActive > activeCutoff);
|
||||||
|
_cachedActiveUsersTime = now;
|
||||||
|
var openSpotsNew = config.CapacityLimit - _cachedActiveUsers;
|
||||||
|
if (openSpotsNew <= 0)
|
||||||
{
|
{
|
||||||
if (_accessQueue.TryRemove(_nowServing, out var nextUser))
|
return true;
|
||||||
|
}
|
||||||
|
int filledSpots = 0;
|
||||||
|
while (filledSpots < openSpotsNew && _nowServing < _nextUnusedTicket)
|
||||||
|
{
|
||||||
|
if (_accessQueue.TryRemove(_nowServing++, out var nextUser))
|
||||||
{
|
{
|
||||||
_queueNumbers.TryRemove(nextUser.UserId, out _);
|
_queueNumbers.TryRemove(nextUser.UserId, out _);
|
||||||
if (nextUser.LastActive < activeCutoff)
|
if (nextUser.LastActive < activeCutoff)
|
||||||
{
|
{
|
||||||
// User is inactive, throw away their ticket
|
// User is inactive, throw away their ticket
|
||||||
_nowServing++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_accessTickets[nextUser.UserId] = new AccessTicket
|
_accessTickets[nextUser.UserId] = new AccessTicket
|
||||||
{
|
{
|
||||||
UserId = nextUser.UserId,
|
UserId = nextUser.UserId,
|
||||||
ExpiresOn = now.AddSeconds(expirationSeconds),
|
ExpiresOn = now.AddSeconds(config.ExpirationSeconds.Value),
|
||||||
LastActive = now
|
LastActive = now
|
||||||
};
|
};
|
||||||
filledSpots++;
|
filledSpots++;
|
||||||
}
|
}
|
||||||
_nowServing++;
|
|
||||||
}
|
}
|
||||||
return filledSpots == openSpots;
|
// Invalidate cache if any users were granted access
|
||||||
|
if (filledSpots > 0)
|
||||||
|
{
|
||||||
|
_cachedActiveUsers = null;
|
||||||
|
_cachedActiveUsersTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
return filledSpots == openSpotsNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessTicket? GetTicket(string userId)
|
public AccessTicket? GetTicket(string userId)
|
||||||
|
@ -101,6 +118,8 @@ namespace AccessQueueService.Data
|
||||||
public void UpsertTicket(AccessTicket ticket)
|
public void UpsertTicket(AccessTicket ticket)
|
||||||
{
|
{
|
||||||
_accessTickets[ticket.UserId] = ticket;
|
_accessTickets[ticket.UserId] = ticket;
|
||||||
|
_cachedActiveUsers = null;
|
||||||
|
_cachedActiveUsersTime = DateTime.MinValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemoveUser(string userId)
|
public bool RemoveUser(string userId)
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace AccessQueueService.Models
|
||||||
public int? ActivitySeconds { get; set; }
|
public int? ActivitySeconds { get; set; }
|
||||||
public int? ExpirationSeconds { get; set; }
|
public int? ExpirationSeconds { get; set; }
|
||||||
public bool? RollingExpiration { get; set; }
|
public bool? RollingExpiration { get; set; }
|
||||||
|
public int? CacheMilliseconds { get; set; }
|
||||||
|
|
||||||
public AccessQueueConfig Clone()
|
public AccessQueueConfig Clone()
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,8 @@ namespace AccessQueueService.Services
|
||||||
ExpirationSeconds = _configuration.GetValue<int>("AccessQueue:ExpirationSeconds"),
|
ExpirationSeconds = _configuration.GetValue<int>("AccessQueue:ExpirationSeconds"),
|
||||||
ActivitySeconds = _configuration.GetValue<int>("AccessQueue:ActivitySeconds"),
|
ActivitySeconds = _configuration.GetValue<int>("AccessQueue:ActivitySeconds"),
|
||||||
CapacityLimit = _configuration.GetValue<int>("AccessQueue:CapacityLimit"),
|
CapacityLimit = _configuration.GetValue<int>("AccessQueue:CapacityLimit"),
|
||||||
RollingExpiration = _configuration.GetValue<bool>("AccessQueue:RollingExpiration")
|
RollingExpiration = _configuration.GetValue<bool>("AccessQueue:RollingExpiration"),
|
||||||
|
CacheMilliseconds = _configuration.GetValue<int>("AccessQueue:CacheMilliseconds")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public AccessQueueConfig GetConfiguration() => _config.Clone();
|
public AccessQueueConfig GetConfiguration() => _config.Clone();
|
||||||
|
@ -53,10 +54,7 @@ namespace AccessQueueService.Services
|
||||||
await _queueLock.WaitAsync();
|
await _queueLock.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hasCapacity = !_accessQueueRepo.DidDequeueUntilFull(
|
var hasCapacity = !_accessQueueRepo.DidDequeueUntilFull(_config);
|
||||||
_config.ActivitySeconds.Value,
|
|
||||||
_config.ExpirationSeconds.Value,
|
|
||||||
_config.CapacityLimit.Value);
|
|
||||||
var existingTicket = _accessQueueRepo.GetTicket(userId);
|
var existingTicket = _accessQueueRepo.GetTicket(userId);
|
||||||
if (existingTicket != null && existingTicket.ExpiresOn > DateTime.UtcNow)
|
if (existingTicket != null && existingTicket.ExpiresOn > DateTime.UtcNow)
|
||||||
{
|
{
|
||||||
|
@ -109,6 +107,10 @@ namespace AccessQueueService.Services
|
||||||
});
|
});
|
||||||
_logger.LogInformation("User {UserId} added to queue. Requests ahead: {RequestsAhead}.", userId, requestsAhead);
|
_logger.LogInformation("User {UserId} added to queue. Requests ahead: {RequestsAhead}.", userId, requestsAhead);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("User {UserId} already in queue. Requests ahead: {RequestsAhead}.", userId, requestsAhead);
|
||||||
|
}
|
||||||
return new AccessResponse
|
return new AccessResponse
|
||||||
{
|
{
|
||||||
ExpiresOn = null,
|
ExpiresOn = null,
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
"RollingExpiration": true,
|
"RollingExpiration": true,
|
||||||
"CleanupIntervalSeconds": 60,
|
"CleanupIntervalSeconds": 60,
|
||||||
"BackupFilePath": "Logs\\backup.json",
|
"BackupFilePath": "Logs\\backup.json",
|
||||||
"BackupIntervalSeconds": 5
|
"BackupIntervalSeconds": 5,
|
||||||
|
"CacheMilliseconds": 1000
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -14,12 +15,43 @@ namespace AccessQueueServiceTests
|
||||||
public class AccessQueueRepoTests
|
public class AccessQueueRepoTests
|
||||||
{
|
{
|
||||||
private readonly TakeANumberAccessQueueRepo _repo;
|
private readonly TakeANumberAccessQueueRepo _repo;
|
||||||
|
private readonly AccessQueueConfig _simpleConfig = new()
|
||||||
|
{
|
||||||
|
ExpirationSeconds = 60,
|
||||||
|
ActivitySeconds = 60,
|
||||||
|
CapacityLimit = 1,
|
||||||
|
RollingExpiration = false,
|
||||||
|
CacheMilliseconds = null
|
||||||
|
};
|
||||||
|
private readonly AccessQueueConfig _configWithCache = new()
|
||||||
|
{
|
||||||
|
ExpirationSeconds = 60,
|
||||||
|
ActivitySeconds = 60,
|
||||||
|
CapacityLimit = 1,
|
||||||
|
RollingExpiration = false,
|
||||||
|
CacheMilliseconds = 100
|
||||||
|
};
|
||||||
|
private AccessQueueConfig SimpleConfigWithCapacity(int capacity) => new()
|
||||||
|
{
|
||||||
|
ExpirationSeconds = 60,
|
||||||
|
ActivitySeconds = 60,
|
||||||
|
CapacityLimit = capacity,
|
||||||
|
RollingExpiration = false,
|
||||||
|
CacheMilliseconds = null
|
||||||
|
};
|
||||||
|
|
||||||
public AccessQueueRepoTests()
|
public AccessQueueRepoTests()
|
||||||
{
|
{
|
||||||
_repo = new TakeANumberAccessQueueRepo();
|
_repo = new TakeANumberAccessQueueRepo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<AccessTicket> GetSimpleTicketList() => new()
|
||||||
|
{
|
||||||
|
new() { UserId = "first", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow },
|
||||||
|
new() { UserId = "second", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow },
|
||||||
|
new() { UserId = "third", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow }
|
||||||
|
};
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetUnexpiredTicketsCount_ReturnsCorrectCount()
|
public void GetUnexpiredTicketsCount_ReturnsCorrectCount()
|
||||||
{
|
{
|
||||||
|
@ -91,7 +123,7 @@ namespace AccessQueueServiceTests
|
||||||
|
|
||||||
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
var ticket = new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
||||||
_repo.Enqueue(ticket);
|
_repo.Enqueue(ticket);
|
||||||
bool result = _repo.DidDequeueUntilFull(60, 60, 1);
|
bool result = _repo.DidDequeueUntilFull(_simpleConfig);
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
Assert.NotNull(_repo.GetTicket("a"));
|
Assert.NotNull(_repo.GetTicket("a"));
|
||||||
}
|
}
|
||||||
|
@ -101,7 +133,7 @@ namespace AccessQueueServiceTests
|
||||||
{
|
{
|
||||||
|
|
||||||
_repo.UpsertTicket(new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow });
|
_repo.UpsertTicket(new AccessTicket { UserId = "a", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow });
|
||||||
bool result = _repo.DidDequeueUntilFull(60, 60, 0);
|
bool result = _repo.DidDequeueUntilFull(SimpleConfigWithCapacity(0));
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +187,7 @@ namespace AccessQueueServiceTests
|
||||||
var active = new AccessTicket { UserId = "active", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
var active = new AccessTicket { UserId = "active", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
||||||
_repo.Enqueue(inactive);
|
_repo.Enqueue(inactive);
|
||||||
_repo.Enqueue(active);
|
_repo.Enqueue(active);
|
||||||
bool result = _repo.DidDequeueUntilFull(5 * 60, 60, 1);
|
bool result = _repo.DidDequeueUntilFull(_simpleConfig);
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
Assert.Null(_repo.GetTicket("inactive"));
|
Assert.Null(_repo.GetTicket("inactive"));
|
||||||
Assert.NotNull(_repo.GetTicket("active"));
|
Assert.NotNull(_repo.GetTicket("active"));
|
||||||
|
@ -164,12 +196,10 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Enqueue_QueuesUsersInOrder()
|
public void Enqueue_QueuesUsersInOrder()
|
||||||
{
|
{
|
||||||
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
|
foreach (var ticket in GetSimpleTicketList())
|
||||||
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
|
{
|
||||||
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow, LastActive = DateTime.UtcNow };
|
_repo.Enqueue(ticket);
|
||||||
_repo.Enqueue(ticket1);
|
}
|
||||||
_repo.Enqueue(ticket2);
|
|
||||||
_repo.Enqueue(ticket3);
|
|
||||||
Assert.Equal(0, _repo.GetRequestsAhead("first"));
|
Assert.Equal(0, _repo.GetRequestsAhead("first"));
|
||||||
Assert.Equal(1, _repo.GetRequestsAhead("second"));
|
Assert.Equal(1, _repo.GetRequestsAhead("second"));
|
||||||
Assert.Equal(2, _repo.GetRequestsAhead("third"));
|
Assert.Equal(2, _repo.GetRequestsAhead("third"));
|
||||||
|
@ -178,14 +208,12 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void DidDequeueUntilFull_DequeuesUsersInOrder()
|
public void DidDequeueUntilFull_DequeuesUsersInOrder()
|
||||||
{
|
{
|
||||||
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
foreach (var ticket in GetSimpleTicketList())
|
||||||
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
{
|
||||||
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
_repo.Enqueue(ticket);
|
||||||
_repo.Enqueue(ticket1);
|
}
|
||||||
_repo.Enqueue(ticket2);
|
|
||||||
_repo.Enqueue(ticket3);
|
|
||||||
|
|
||||||
bool result = _repo.DidDequeueUntilFull(60 * 60, 60, 1);
|
bool result = _repo.DidDequeueUntilFull(_simpleConfig);
|
||||||
|
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
Assert.NotNull(_repo.GetTicket("first"));
|
Assert.NotNull(_repo.GetTicket("first"));
|
||||||
|
@ -193,17 +221,33 @@ namespace AccessQueueServiceTests
|
||||||
Assert.Null(_repo.GetTicket("third"));
|
Assert.Null(_repo.GetTicket("third"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DidDequeuedUntilFull_CachesActiveTickets_WhenCacheMillisSet()
|
||||||
|
{
|
||||||
|
foreach (var ticket in GetSimpleTicketList())
|
||||||
|
{
|
||||||
|
_repo.Enqueue(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.True(_repo.DidDequeueUntilFull(_configWithCache));
|
||||||
|
Assert.NotNull(_repo.GetTicket("first"));
|
||||||
|
Assert.Null(_repo.GetTicket("second"));
|
||||||
|
Assert.Null(_repo.GetTicket("third"));
|
||||||
|
|
||||||
|
Assert.True(_repo.DidDequeueUntilFull(_configWithCache));
|
||||||
|
Assert.Null(_repo.GetTicket("second"));
|
||||||
|
Assert.Null(_repo.GetTicket("third"));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Optimize_MaintainsQueueOrder()
|
public void Optimize_MaintainsQueueOrder()
|
||||||
{
|
{
|
||||||
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
foreach (var ticket in GetSimpleTicketList())
|
||||||
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
{
|
||||||
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
_repo.Enqueue(ticket);
|
||||||
_repo.Enqueue(ticket1);
|
}
|
||||||
_repo.Enqueue(ticket2);
|
|
||||||
_repo.Enqueue(ticket3);
|
|
||||||
|
|
||||||
_repo.DidDequeueUntilFull(60 * 60, 60, 1);
|
_repo.DidDequeueUntilFull(_simpleConfig);
|
||||||
_repo.Optimize();
|
_repo.Optimize();
|
||||||
|
|
||||||
Assert.NotNull(_repo.GetTicket("first"));
|
Assert.NotNull(_repo.GetTicket("first"));
|
||||||
|
@ -211,7 +255,7 @@ namespace AccessQueueServiceTests
|
||||||
Assert.Equal(1, _repo.GetRequestsAhead("third"));
|
Assert.Equal(1, _repo.GetRequestsAhead("third"));
|
||||||
Assert.Equal(0ul, _repo._nowServing);
|
Assert.Equal(0ul, _repo._nowServing);
|
||||||
|
|
||||||
_repo.DidDequeueUntilFull(60 * 60, 60, 2);
|
_repo.DidDequeueUntilFull(SimpleConfigWithCapacity(2));
|
||||||
Assert.NotNull(_repo.GetTicket("second"));
|
Assert.NotNull(_repo.GetTicket("second"));
|
||||||
Assert.Equal(0, _repo.GetRequestsAhead("third"));
|
Assert.Equal(0, _repo.GetRequestsAhead("third"));
|
||||||
}
|
}
|
||||||
|
@ -219,16 +263,13 @@ namespace AccessQueueServiceTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Enqueue_MaintainsQueueOrder_WhenMaxValueExceeded()
|
public void Enqueue_MaintainsQueueOrder_WhenMaxValueExceeded()
|
||||||
{
|
{
|
||||||
var ticket1 = new AccessTicket { UserId = "first", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
|
||||||
var ticket2 = new AccessTicket { UserId = "second", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
|
||||||
var ticket3 = new AccessTicket { UserId = "third", ExpiresOn = DateTime.UtcNow.AddMinutes(1), LastActive = DateTime.UtcNow };
|
|
||||||
|
|
||||||
_repo._nowServing = long.MaxValue - 1;
|
_repo._nowServing = long.MaxValue - 1;
|
||||||
_repo._nextUnusedTicket = long.MaxValue - 1;
|
_repo._nextUnusedTicket = long.MaxValue - 1;
|
||||||
|
|
||||||
_repo.Enqueue(ticket1);
|
foreach (var ticket in GetSimpleTicketList())
|
||||||
_repo.Enqueue(ticket2);
|
{
|
||||||
_repo.Enqueue(ticket3);
|
_repo.Enqueue(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
Assert.Equal(0ul, _repo._nowServing);
|
Assert.Equal(0ul, _repo._nowServing);
|
||||||
Assert.Equal(3ul, _repo._nextUnusedTicket);
|
Assert.Equal(3ul, _repo._nextUnusedTicket);
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace AccessQueueServiceTests
|
||||||
const int ACT_MILLIS = 1000 * ACT_SECONDS;
|
const int ACT_MILLIS = 1000 * ACT_SECONDS;
|
||||||
const int CAP_LIMIT = 5;
|
const int CAP_LIMIT = 5;
|
||||||
const int BULK_COUNT = 10000;
|
const int BULK_COUNT = 10000;
|
||||||
|
const int CACHE_MILLIS = 1000;
|
||||||
private readonly AccessService _accessService;
|
private readonly AccessService _accessService;
|
||||||
|
|
||||||
public AccessServiceTests()
|
public AccessServiceTests()
|
||||||
|
@ -25,7 +26,8 @@ namespace AccessQueueServiceTests
|
||||||
{ "AccessQueue:ExpirationSeconds", $"{EXP_SECONDS}" },
|
{ "AccessQueue:ExpirationSeconds", $"{EXP_SECONDS}" },
|
||||||
{ "AccessQueue:ActivitySeconds", $"{ACT_SECONDS}" },
|
{ "AccessQueue:ActivitySeconds", $"{ACT_SECONDS}" },
|
||||||
{ "AccessQueue:CapacityLimit", $"{CAP_LIMIT}" },
|
{ "AccessQueue:CapacityLimit", $"{CAP_LIMIT}" },
|
||||||
{ "AccessQueue:RollingExpiration", "true" }
|
{ "AccessQueue:RollingExpiration", "true" },
|
||||||
|
{ "AccessQueue:CacheMilliseconds", $"{CACHE_MILLIS}" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var configuration = new ConfigurationBuilder()
|
var configuration = new ConfigurationBuilder()
|
||||||
|
@ -87,9 +89,9 @@ namespace AccessQueueServiceTests
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
Assert.Null(response.ExpiresOn);
|
Assert.Null(response.ExpiresOn);
|
||||||
Assert.True(response.RequestsAhead == CAP_LIMIT);
|
Assert.True(response.RequestsAhead == CAP_LIMIT);
|
||||||
Assert.Equal(5, _accessService.UnexpiredTicketsCount);
|
Assert.Equal(CAP_LIMIT, _accessService.UnexpiredTicketsCount);
|
||||||
Assert.Equal(5, _accessService.ActiveTicketsCount);
|
Assert.Equal(CAP_LIMIT, _accessService.ActiveTicketsCount);
|
||||||
Assert.Equal(6, _accessService.QueueCount);
|
Assert.Equal(CAP_LIMIT + 1, _accessService.QueueCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue