Skip to content

Instantly share code, notes, and snippets.

@leandromoh
Last active December 8, 2021 19:48
Show Gist options
  • Save leandromoh/1fc330a851a466e3f64b2c29b27760b9 to your computer and use it in GitHub Desktop.
Save leandromoh/1fc330a851a466e3f64b2c29b27760b9 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Timers;
public class CustomCache
{
private readonly ConcurrentDictionary<string, Task<(object result, DateTime expirationDate)>> dic = new();
private readonly TimeSpan _threshold;
private readonly Timer _timer;
public CustomCache(TimeSpan threshold)
{
_threshold = threshold;
_timer = new(TimeSpan.FromMinutes(15).Milliseconds);
_timer.Elapsed += OnTimedEvent;
_timer.AutoReset = true;
_timer.Enabled = true;
}
private async void OnTimedEvent(object source, ElapsedEventArgs e)
{
foreach (var (key, task) in dic)
{
var resp = await task;
if (IsExpirationValid(resp.expirationDate) is false)
dic.TryRemove(key, out var _);
}
}
private bool IsExpirationValid(DateTime expirationDate)
{
return DateTime.UtcNow < expirationDate - _threshold;
}
public async Task<TResult> GetOrAddAsync<TResult>(string key, Func<string, Task<(TResult result, DateTime expirationDate)>> function)
{
var usedCache = true;
var resp = await dic.GetOrAdd(key, async k =>
{
usedCache = false;
return await function(k);
});
if (usedCache is false || IsExpirationValid(resp.expirationDate))
{
return (TResult)resp.result;
}
dic.TryRemove(key, out var _);
resp = await dic.GetOrAdd(key, async k => await function(k));
return (TResult)resp.result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment