I'm unsure whether the following is thread safe. I want to say it is because the static state is only assigned to within the lock. However I'm more of a js programmer so this is out of my comfort zone and would appreciate a more seasoned pair of eyes.
The purpose is simple - this class intends to cache application settings (e.g. help desk phone number) from the database so we're querying the database a maximum once every 3 minutes.
If there's a library or builtin class intended for this then please let me know. I googled for a while and struggled to find pertinent info.
public static class AppSettings
{
private static readonly object stateLock = new object();
private static TaskCompletionSource<AppSettingsModel> Cached { get; set; }
private static DateTime? LastFetched { get; set; }
public static async Task<AppSettingsModel> Get()
{
TaskCompletionSource<AppSettingsModel> prevCache;
bool returnCache = false;
lock (stateLock)
{
prevCache = Cached;
if (LastFetched.HasValue)
{
if (DateTime.Now.Subtract(LastFetched.Value).TotalMinutes >= 3)
Cached = null;
else if (Cached != null)
returnCache = true;
}
if (!returnCache) {
Cached = new TaskCompletionSource<AppSettingsModel>();
LastFetched = DateTime.Now;
}
}
if (returnCache)
return await Cached.Task;
try
{
Cached.SetResult(await GetAppSettingsFromDB());
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
if (prevCache != null)
Cached.SetResult(await prevCache.Task);
else
Cached.SetResult(new AppSettingsModel());
}
return await Cached.Task;
}
}