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; } }