I'm writing a method to throttle duplicate requests taking place within multiple HttpModule instances within a web application.
Currently, I have the following setup:
// Container for semaphores
private static readonly ConcurrentDictionary<string, SemaphoreSlim>
SemaphoreSlims = new ConcurrentDictionary<string, SemaphoreSlim>();
// Wrapper for getting semaphore
private static SemaphoreSlim GetSemaphoreSlim(string id)
{
return SemaphoreSlims.GetOrAdd(id, new SemaphoreSlim(1, 1));
}
private async Task ProcessImageAsync(HttpContext context)
{
// `hash` is the request path hashed.
SemaphoreSlim semaphore = GetSemaphoreSlim(hash);
await semaphore.WaitAsync();
try
{
// Do awaitable task
}
finally
{
semaphore.Release();
}
}
This will work but I have no way of disposing of the semaphore instances since I need to preserve the ConcurrentDictionary and cannot dispose of a semaphore within the Dispose() method for that HttpModule instance as it could be currently waiting in another instance.
By my calculation it would take up ~156 megabytes of memory for 1 million items stored in the dictionary. It's not a massive amount but I'd really like it to be scalable and somehow find a way to clean up after myself.
Is this a sensible pattern and is there a way I can improve on it?