/// <summary> /// This method attempts to returned a cached value, in the case of a /// cache miss the fetchFunc will be used to provide a fresh value which /// is then returned. In the case of a cache hit where the cache item is /// considered stale (but not expired) as determined by <paramref name="refreshInterval"/> /// the stale value will be produced first, followed by the fresh value /// when the fetch func completes. /// </summary> /// <param name="blobCache">The cache to retrieve the object from.</param> /// <param name="key">The key to look up the cache value with.</param> /// <param name="fetchFunc">The fetch function.</param> /// <param name="refreshInterval"> /// Cache objects with an age exceeding this value will be treated as stale /// and the fetch function will be invoked to refresh it. /// </param> /// <param name="maxCacheDuration"> /// The maximum age of a cache object before the object is treated as /// expired and unusable. Cache objects older than this will be treated /// as a cache miss. /// </param> public static IObservable <byte[]> GetAndRefresh( this IBlobCache blobCache, string key, Func <IObservable <byte[]> > fetchFunc, TimeSpan refreshInterval, TimeSpan maxCacheDuration) { return(Observable.Defer(() => { var absoluteExpiration = blobCache.Scheduler.Now + maxCacheDuration; try { return blobCache.GetAndFetchLatestBytes( key, fetchFunc, createdAt => IsExpired(blobCache, createdAt, refreshInterval), absoluteExpiration); } catch (Exception exc) { return Observable.Throw <byte[]>(exc); } })); }