private void StartBackgroundFetch <T>(string key, Func <Task <T> > func, TinyCachePolicy policy, Action <T> onUpdate) { if (policy.UpdateCacheTimeout > 0) { if (ShouldFetch(policy.UpdateCacheTimeout, key)) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Delay((int)policy.UpdateCacheTimeout).ContinueWith(async(arg) => { try { var newvalue = await TimeoutAfter <T>(func, policy.BackgroundFetchTimeout); onUpdate?.Invoke(newvalue); Store(key, newvalue, policy); } catch (Exception ex) { if (policy.ReportExceptionsOnBackgroundFetch) { OnError?.Invoke(policy, ex); policy.ExceptionHandler?.Invoke(ex, true); } } }); } #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } }
/// <summary> /// Fetch using policy /// </summary> /// <returns>The data from function or cache depending on policy.</returns> /// <param name="key">Cache key.</param> /// <param name="func">Function for populating cache</param> /// <param name="policy">Policy.</param> /// <param name="onUpdate">Method to call when data is updated in the background.</param> /// <typeparam name="T">Return type of function and cache object.</typeparam> public async Task <T> RunAsync <T>(string key, Func <Task <T> > func, TinyCachePolicy policy = null, Action <T> onUpdate = null) { var genericType = typeof(T); object ret = Storage.Get(key, genericType); if (ret == null && SecondaryStorage != null) { ret = SecondaryStorage.Get(key, genericType); } policy = policy ?? defaultPolicy; if (ret == null) { ret = await func(); Store(key, ret, policy); } else if (policy.UseCacheFirstFunction == null || !policy.UseCacheFirstFunction()) { if (policy.Mode == TinyCacheModeEnum.FetchFirst) { try { var realFetch = await TimeoutAfter(func, policy.FetchTimeout); if (!(realFetch is T)) { ret = realFetch; Store(key, realFetch, policy); } } catch (Exception ex) { OnError?.Invoke(policy, ex); policy.ExceptionHandler?.Invoke(ex, true); } } } StartBackgroundFetch(key, func, policy, onUpdate); AddLastFetch(key); return((ret == null) ? default(T) : (T)ret); }
private void Store(string key, object val, TinyCachePolicy policy) { if (val != null) { AddLastFetch(key); if (Storage.Store(key, val)) { policy?.UpdateHandler?.Invoke(key, val); OnUpdate?.Invoke(val, new CacheUpdatedEvt(key, val)); if (SecondaryStorage != null) { Task.Delay(10).ContinueWith((a) => { SecondaryStorage.Store(key, val, false); }); } } } }
/// <summary> /// Sets the base policy wich will be used if not specified in each request. /// </summary> /// <param name="tinyCachePolicy">Tiny cache policy.</param> public void SetBasePolicy(TinyCachePolicy tinyCachePolicy) { defaultPolicy = tinyCachePolicy; }