public async Task <T> GetEntryFromCache <T>(string endpoint, string identifier, GetLiveEndpointResultDelegate <T> cacheSetCall, DateTimeOffset cacheExpiration, CacheDurationType cacheDurationType = CacheDurationType.Absolute, bool persistInMemory = true, bool persistOnDisk = false) where T : class { // Check memory cache first var responseItem = persistInMemory ? Get(identifier, endpoint) as T : null; // If not in memory cache, check file system cache if (responseItem == null) { responseItem = persistOnDisk ? await GetFromFsCache(endpoint, identifier, cacheSetCall, cacheExpiration, cacheDurationType) : null; if (responseItem == null) { return(await cacheSetCall.Invoke(identifier, endpoint)); } if (persistInMemory) { var policy = new CacheItemPolicy(); if (cacheDurationType == CacheDurationType.Absolute) { policy.AbsoluteExpiration = cacheExpiration; } else if (cacheDurationType == CacheDurationType.Sliding) { policy.SlidingExpiration = cacheExpiration.Offset; } base.Set(GetCacheItemFqn(identifier, endpoint), responseItem, policy); } } return(responseItem); }
public async Task <T> GetFromFsCache <T>(string endpoint, string identifier, GetLiveEndpointResultDelegate <T> cacheSetCall, DateTimeOffset cacheExpiration, CacheDurationType cacheDurationType = CacheDurationType.Absolute) where T : class { string niceEndpointName = GetEndpointNiceName(endpoint); // Cache it to the file system, if that's enabled or available if (cacheExpiration.Offset.TotalSeconds > 0 && !string.IsNullOrEmpty(niceEndpointName) && !string.IsNullOrEmpty(this.CacheDirectory)) { string endpointCacheRoot = $"{niceEndpointName}{CACHE_ENDPOINT_EXTENSION}"; // TODO: For now while we aren't updating fs cache in this function if (!File.Exists(Path.Combine(this.CacheDirectory, endpointCacheRoot))) { return(null); } using (var endpointFileStream = new FileStream(Path.Combine(this.CacheDirectory, endpointCacheRoot), FileMode.Open)) { using (var endpointArchive = new ZipArchive(endpointFileStream, ZipArchiveMode.Update)) { string entryName = identifier + CACHE_ENTRY_EXTENSION; var entryFind = endpointArchive.GetEntry(entryName); // Where we will store the result T result; if (entryFind == null || entryFind.LastWriteTime.Subtract(DateTime.Now) > cacheExpiration.Offset) { entryFind?.Delete(); result = await cacheSetCall.Invoke(identifier, endpoint); // TODO: Instead of doing this now, queue it and do them all at once to avoid IO errors // Add new cache entry into zip //entryFind = endpointArchive.CreateEntry(entryName, CompressionLevel.Fastest); //using (var entryStream = entryFind.Open()) { // ProtoBuf.Serializer.Serialize(entryStream, result); //} } else { result = ProtoBuf.Serializer.Deserialize <T>(entryFind.Open()); // If cache duration mode is sliding, then touch the timestamp to update it from this access if (cacheDurationType == CacheDurationType.Sliding) { entryFind.LastWriteTime = DateTimeOffset.Now; } } return(result); } } } return(null); }