Compare commits

...

1 Commits

Author SHA1 Message Date
henry b1b1b44e0f wip - trying to move expensive alculation to background 2025-05-16 21:21:07 -04:00
5 changed files with 71 additions and 7 deletions

View File

@ -26,6 +26,19 @@ builder.Services.AddHostedService<AccessQueueBackgroundService>();
var app = builder.Build();
// Configure TakeANumberAccessQueueRepo active users cache
using (var scope = app.Services.CreateScope())
{
var config = scope.ServiceProvider.GetRequiredService<IConfiguration>();
var repo = scope.ServiceProvider.GetRequiredService<IAccessQueueRepo>() as TakeANumberAccessQueueRepo;
if (repo != null)
{
int activeSeconds = config.GetValue<int>("AccessQueue:ActivitySeconds", 2);
int updateInterval = config.GetValue<int>("AccessQueue:ActiveUsersUpdateIntervalSeconds", 2);
repo.ConfigureActiveUsersCache(activeSeconds, updateInterval);
}
}
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{

View File

@ -6,13 +6,14 @@
}
},
"AccessQueue": {
"CapacityLimit": 3, // Maximum number of active users
"ActivitySeconds": 2, // Time since last access before a user is considered inactive
"ExpirationSeconds": 10, // 12 hours - Time before a user access is revoked
"RollingExpiration": true // Whether to extend expiration time on access
"CapacityLimit": 3,
"ActivitySeconds": 2,
"ExpirationSeconds": 10,
"RollingExpiration": true,
"ActiveUsersUpdateIntervalSeconds": 2
},
"AccessQueuePlayground": {
"RefreshRateMilliseconds": 200 // How often to re-request access and update the UI
"RefreshRateMilliseconds": 200
},
"AllowedHosts": "*"
}

View File

@ -1,5 +1,6 @@
using AccessQueueService.Models;
using Microsoft.Extensions.Configuration;
using System.Threading;
namespace AccessQueueService.Data
{
@ -12,6 +13,12 @@ namespace AccessQueueService.Data
private ulong _nowServing = 0;
private ulong _nextUnusedTicket = 0;
private int _cachedActiveUsers = 0;
private int _activeSeconds = 60; // default, can be set from config
private Timer? _activeUsersUpdateTimer;
private int _activeUsersUpdateIntervalSeconds = 10; // default, can be set from config
private readonly object _activeUsersLock = new();
public int GetUnexpiredTicketsCount() => _accessTickets.Count(t => t.Value.ExpiresOn > DateTime.UtcNow);
public int GetActiveTicketsCount(DateTime activeCutoff) => _accessTickets
.Count(t => t.Value.ExpiresOn > DateTime.UtcNow && t.Value.LastActive > activeCutoff);
@ -54,7 +61,8 @@ namespace AccessQueueService.Data
{
var now = DateTime.UtcNow;
var activeCutoff = now.AddSeconds(-activeSeconds);
var numberOfActiveUsers = _accessTickets.Count(t => t.Value.ExpiresOn > now && t.Value.LastActive > activeCutoff);
// Use cached value instead of recalculating
var numberOfActiveUsers = GetCachedActiveUsers();
var openSpots = capacityLimit - numberOfActiveUsers;
if(openSpots <= 0)
{
@ -104,5 +112,33 @@ namespace AccessQueueService.Data
}
return _accessTickets.Remove(userId);
}
public void ConfigureActiveUsersCache(int activeSeconds, int updateIntervalSeconds)
{
_activeSeconds = activeSeconds;
_activeUsersUpdateIntervalSeconds = updateIntervalSeconds;
_activeUsersUpdateTimer?.Dispose();
_activeUsersUpdateTimer = new Timer(_ => UpdateActiveUsersCache(), null, 0, _activeUsersUpdateIntervalSeconds * 1000);
}
private void UpdateActiveUsersCache()
{
var now = DateTime.UtcNow;
var activeCutoff = now.AddSeconds(-_activeSeconds);
int count = 0;
lock (_activeUsersLock)
{
count = _accessTickets.Count(t => t.Value.ExpiresOn > now && t.Value.LastActive > activeCutoff);
_cachedActiveUsers = count;
}
}
public int GetCachedActiveUsers()
{
lock (_activeUsersLock)
{
return _cachedActiveUsers;
}
}
}
}

View File

@ -22,6 +22,19 @@ builder.Services.AddHostedService<AccessCleanupBackgroundService>();
var app = builder.Build();
// Configure TakeANumberAccessQueueRepo active users cache
using (var scope = app.Services.CreateScope())
{
var config = scope.ServiceProvider.GetRequiredService<IConfiguration>();
var repo = scope.ServiceProvider.GetRequiredService<IAccessQueueRepo>() as TakeANumberAccessQueueRepo;
if (repo != null)
{
int activeSeconds = config.GetValue<int>("AccessQueue:ActivitySeconds", 900);
int updateInterval = config.GetValue<int>("AccessQueue:ActiveUsersUpdateIntervalSeconds", 10);
repo.ConfigureActiveUsersCache(activeSeconds, updateInterval);
}
}
if (app.Environment.IsDevelopment())
{
app.UseSwagger();

View File

@ -28,7 +28,8 @@
"ActivitySeconds": 900,
"ExpirationSeconds": 43200,
"RollingExpiration": true,
"CleanupIntervalSeconds": 60
"CleanupIntervalSeconds": 60,
"ActiveUsersUpdateIntervalSeconds": 10
},
"AllowedHosts": "*"
}