diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..035bb09 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +* @aheintz +* @norcetech/product-squad \ No newline at end of file diff --git a/.github/workflows/auto-reviewers.yml b/.github/workflows/auto-reviewers.yml new file mode 100644 index 0000000..b4aa751 --- /dev/null +++ b/.github/workflows/auto-reviewers.yml @@ -0,0 +1,19 @@ +name: AI Code Review +on: + pull_request: + types: [opened, synchronize] # triggers on new PR and each commit + +jobs: + ai-review: + runs-on: ubuntu-latest + steps: + + - name: Run AI Reviewer + uses: propstreet/reviewer@v2 + with: + azureOpenAIKey: ${{ secrets.AZURE_PR_AI_OPENAI_API_KEY }} + azureOpenAIEndpoint: ${{ secrets.AZURE_PR_AI_OPENAI_REASONING_ENDPOINT }} + azureOpenAIDeployment: ${{ secrets.AZURE_PR_AI_OPENAI_REASONING_DEPLOYMENT }} + azureOpenAIVersion: ${{ secrets.AZURE_PR_AI_OPENAI_REASONING_VERSION }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/jira-info-on-pr.yml b/.github/workflows/jira-info-on-pr.yml new file mode 100644 index 0000000..549d07e --- /dev/null +++ b/.github/workflows/jira-info-on-pr.yml @@ -0,0 +1,18 @@ +name: Jira Info Automation + +on: + pull_request: + types: + - opened + - ready_for_review + - reopened + workflow_dispatch: + +permissions: + contents: read + pull-requests: write + +jobs: + add-jira-info: + uses: NorceTech/azure-devops-templates/.github/workflows/add-jira-info-on-pr.yml@main + secrets: inherit diff --git a/HzMemoryCache/Diagnostics/HzActivities.cs b/HzMemoryCache/Diagnostics/HzActivities.cs index fac88e9..04c68bb 100644 --- a/HzMemoryCache/Diagnostics/HzActivities.cs +++ b/HzMemoryCache/Diagnostics/HzActivities.cs @@ -10,12 +10,11 @@ public static class HzActivities public static class Names { - public const string Set = "set from cache"; public const string SetRedis = "set to redis"; - public const string Get = "get from cache"; + public const string Get = "get"; public const string GetRedis = "get from redis"; - public const string GetOrSet = "get or set from cache"; - public const string GetOrSetBatch = "get or set batch from cache"; + public const string GetOrSetCacheMiss = "get or set on cache miss"; + public const string GetOrSetBatch = "get or set batch"; public const string GetBatchRedis = "get batch from redis"; public const string Remove = "remove"; public const string RemoveByPattern = "remove by pattern"; @@ -29,7 +28,6 @@ public static class Names public const string Subscribe = "subscribe"; public const string ValueChanged = "value changed"; public const string EvictExpired = "evict expired"; - public const string GetStatistics = "get statistics"; public const string ProcessExpiredEviction = "process expired eviction"; public const string AcquireLock = "acquire lock"; diff --git a/HzMemoryCache/HzCacheMemoryLocker.cs b/HzMemoryCache/HzCacheMemoryLocker.cs index 9364b7b..89911ac 100644 --- a/HzMemoryCache/HzCacheMemoryLocker.cs +++ b/HzMemoryCache/HzCacheMemoryLocker.cs @@ -68,7 +68,7 @@ private SemaphoreSlim GetSemaphore(string cacheName, string cacheInstanceId, str if (logger?.IsEnabled(LogLevel.Warning) ?? false) { logger.Log(LogLevel.Warning, exc, - "FUSION [N={CacheName} I={CacheInstanceId}] (K={CacheKey}): an error occurred while trying to dispose a SemaphoreSlim in the memory locker", + "HZ [N={CacheName} I={CacheInstanceId}] (K={CacheKey}): an error occurred while trying to dispose a SemaphoreSlim in the memory locker", cacheName, cacheInstanceId, key); } } @@ -87,7 +87,7 @@ public async ValueTask AcquireLockAsync(string cacheName, string cacheIn if (logger?.IsEnabled(LogLevel.Trace) ?? false) { - logger.Log(LogLevel.Trace, "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): waiting to acquire the LOCK", cacheName, + logger.Log(LogLevel.Trace, "HZ [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): waiting to acquire the LOCK", cacheName, cacheInstanceId, operationId, key); } @@ -98,7 +98,7 @@ public async ValueTask AcquireLockAsync(string cacheName, string cacheIn // LOCK ACQUIRED if (logger?.IsEnabled(LogLevel.Trace) ?? false) { - logger.Log(LogLevel.Trace, "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK acquired", cacheName, cacheInstanceId, + logger.Log(LogLevel.Trace, "HZ [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK acquired", cacheName, cacheInstanceId, operationId, key); } } @@ -107,7 +107,7 @@ public async ValueTask AcquireLockAsync(string cacheName, string cacheIn // LOCK TIMEOUT if (logger?.IsEnabled(LogLevel.Trace) ?? false) { - logger.Log(LogLevel.Trace, "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK timeout", cacheName, cacheInstanceId, + logger.Log(LogLevel.Trace, "HZ [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK timeout", cacheName, cacheInstanceId, operationId, key); } } @@ -125,7 +125,7 @@ public async ValueTask AcquireLockAsync(string cacheName, string cacheIn if (logger?.IsEnabled(LogLevel.Trace) ?? false) { - logger.Log(LogLevel.Trace, "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): waiting to acquire the LOCK", cacheName, + logger.Log(LogLevel.Trace, "HZ [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): waiting to acquire the LOCK", cacheName, cacheInstanceId, operationId, key); } @@ -136,7 +136,7 @@ public async ValueTask AcquireLockAsync(string cacheName, string cacheIn // LOCK ACQUIRED if (logger?.IsEnabled(LogLevel.Trace) ?? false) { - logger.Log(LogLevel.Trace, "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK acquired", cacheName, cacheInstanceId, + logger.Log(LogLevel.Trace, "HZ [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK acquired", cacheName, cacheInstanceId, operationId, key); } } @@ -145,7 +145,7 @@ public async ValueTask AcquireLockAsync(string cacheName, string cacheIn // LOCK TIMEOUT if (logger?.IsEnabled(LogLevel.Trace) ?? false) { - logger.Log(LogLevel.Trace, "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK timeout", cacheName, cacheInstanceId, + logger.Log(LogLevel.Trace, "HZ [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): LOCK timeout", cacheName, cacheInstanceId, operationId, key); } } @@ -173,7 +173,7 @@ public void ReleaseLock(string cacheName, string cacheInstanceId, string operati if (logger?.IsEnabled(LogLevel.Warning) ?? false) { logger.Log(LogLevel.Warning, exc, - "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): an error occurred while trying to release a SemaphoreSlim in the memory locker", + "HZ [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): an error occurred while trying to release a SemaphoreSlim in the memory locker", cacheName, cacheInstanceId, operationId, key); } activity?.AddTag(Tags.Names.ReleasedLock, false); diff --git a/HzMemoryCache/HzMemoryCache.cs b/HzMemoryCache/HzMemoryCache.cs index a3bb769..6ee70f8 100644 --- a/HzMemoryCache/HzMemoryCache.cs +++ b/HzMemoryCache/HzMemoryCache.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Reactive.Concurrency; -using System.Reactive.Joins; using System.Reactive.Linq; using System.Text.RegularExpressions; using System.Threading; @@ -46,7 +45,6 @@ public HzMemoryCache(HzCacheOptions? options = null) public int Count => dictionary.Count; public long SizeInBytes => dictionary.Values.Sum(ttlv => ttlv.sizeInBytes); - public void RemoveByPattern(string pattern, bool sendNotification = true) { using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.RemoveByPattern, HzActivities.Area.HzMemoryCache, pattern: pattern, sendNotification: sendNotification); @@ -79,7 +77,7 @@ public void EvictExpired() { foreach (var p in dictionary.Where(p => p.Value.IsExpired())) { - RemoveItem(p.Key, CacheItemChangeType.Expire, true); + RemoveItem(p.Key, CacheItemChangeType.Expire, false); } } finally @@ -91,6 +89,7 @@ public void EvictExpired() public void Clear() { + using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Clear, HzActivities.Area.HzMemoryCache); var kvps = dictionary.ToArray(); dictionary.Clear(); foreach (var kv in kvps) @@ -104,8 +103,6 @@ public void Clear() /// public T? Get(string key) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Get, HzActivities.Area.HzMemoryCache); - var defaultValue = default(T); if (!dictionary.TryGetValue(key, out var ttlValue)) @@ -144,8 +141,6 @@ public void Set(string key, T? value) /// public void Set(string key, T? value, TimeSpan ttl) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Set, HzActivities.Area.HzMemoryCache); - var v = new TTLValue(key, value, ttl, updateChecksumAndSerializeQueue, options.notificationType, (tv, objectData) => NotifyItemChange(key, CacheItemChangeType.AddOrUpdate, tv, objectData), options.compressionThreshold); dictionary[key] = v; @@ -156,14 +151,14 @@ public void Set(string key, T? value, TimeSpan ttl) /// public T? GetOrSet(string key, Func valueFactory, TimeSpan ttl, long maxMsToWaitForFactory = 10000) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSet, HzActivities.Area.HzMemoryCache, key: key); - var value = Get(key); if (!IsNullOrDefault(value)) { return value; } + using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSetCacheMiss, HzActivities.Area.HzMemoryCache, key: key); + options.logger?.LogDebug("Cache miss for key {Key}, calling value factory", key); var factoryLock = memoryLocker.AcquireLock(options.applicationCachePrefix, options.instanceId, "GET", key, TimeSpan.FromMilliseconds(maxMsToWaitForFactory), @@ -174,7 +169,6 @@ public void Set(string key, T? value, TimeSpan ttl) throw new Exception($"Could not acquire lock for key {key}"); } - try { value = Get(key); @@ -182,11 +176,8 @@ public void Set(string key, T? value, TimeSpan ttl) { return value; } - using (var executeActivity = - HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.ExecuteFactory, - HzActivities.Area.HzMemoryCache, key: key)) + using (var executeActivity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.ExecuteFactory, HzActivities.Area.HzMemoryCache, key: key)) { - value = valueFactory(key); } @@ -211,8 +202,7 @@ public IList GetOrSetBatch(IList keys, Func, List GetOrSetBatch(IList keys, Func, List>> valueFactory, TimeSpan ttl) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSetBatch, HzActivities.Area.HzMemoryCache, key: string.Join(",",keys??new List())); - + using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSetBatch, HzActivities.Area.HzMemoryCache, key: string.Join(",", keys ?? new List())); var cachedItems = keys.Select(key => new KeyValuePair(key, Get(key))); var missingKeys = cachedItems.Where(kvp => IsNullOrDefault(kvp.Value)).Select(kvp => kvp.Key).ToList(); @@ -236,7 +226,6 @@ public IList GetOrSetBatch(IList keys, Func, List v.Value is not null).Select(kv => kv.Value).ToList(); } - /// /// @see /// @@ -245,7 +234,6 @@ public bool Remove(string key) return Remove(key, options.notificationType != NotificationType.None); } - /// /// @see /// @@ -267,7 +255,6 @@ public void Dispose() Dispose(true); } - public IEnumerator> GetEnumerator() { foreach (var kvp in dictionary) @@ -279,17 +266,11 @@ public IEnumerator> GetEnumerator() } } - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - private object? AcquireLock(string operation, string key) - { - return memoryLocker.AcquireLock(options.applicationCachePrefix, options.instanceId, operation, key, TimeSpan.FromSeconds(10), options.logger, CancellationToken.None); - } - private void ReleaseLock(object? memoryLock, string? operation, string key) { memoryLocker.ReleaseLock(options.applicationCachePrefix, options.instanceId, operation, key, memoryLock, options.logger); @@ -340,8 +321,6 @@ private async Task ProcessExpiredEviction() private bool RemoveItem(string key, CacheItemChangeType changeType, bool sendNotification, Func? areEqualFunc = null) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.RemoveItem, HzActivities.Area.HzMemoryCache, key: key); - var result = !(!dictionary.TryGetValue(key, out TTLValue ttlValue) || (areEqualFunc != null && areEqualFunc.Invoke(ttlValue.checksum))); if (result) @@ -363,8 +342,6 @@ private bool RemoveItem(string key, CacheItemChangeType changeType, bool sendNot private void NotifyItemChange(string key, CacheItemChangeType changeType, TTLValue ttlValue, byte[]? objectData = null, bool isPattern = false) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.NotifyItemChange, HzActivities.Area.HzMemoryCache, key: key); - options.valueChangeListener(key, changeType, ttlValue, objectData, isPattern); } diff --git a/HzMemoryCache/HzMemoryCacheAsync.cs b/HzMemoryCache/HzMemoryCacheAsync.cs index 083658c..2633dc2 100644 --- a/HzMemoryCache/HzMemoryCacheAsync.cs +++ b/HzMemoryCache/HzMemoryCacheAsync.cs @@ -18,21 +18,20 @@ public Task SetAsync(string key, T? value) public Task SetAsync(string key, T? value, TimeSpan ttl) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Set, HzActivities.Area.HzMemoryCache, async: true, key: key); Set(key, value, ttl); return Task.CompletedTask; } public async Task GetOrSetAsync(string key, Func> valueFactory, TimeSpan ttl, long maxMsToWaitForFactory = 10000) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSet, HzActivities.Area.HzMemoryCache, async: true, key: key); - var value = Get(key); if (!IsNullOrDefault(value)) { return value; } + using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSetCacheMiss, HzActivities.Area.HzMemoryCache, async: true, key: key); + options.logger?.LogDebug("Cache miss for key {Key}, calling value factory", key); var factoryLock = await memoryLocker.AcquireLockAsync(options.applicationCachePrefix, options.instanceId, "GET", key, TimeSpan.FromMilliseconds(maxMsToWaitForFactory), @@ -151,7 +150,6 @@ public async Task RemoveByPatternAsync(string pattern, bool sendNotification = t public async Task GetAsync(string key) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Get, HzActivities.Area.HzMemoryCache, async: true, key: key); var defaultValue = default(T); if (!dictionary.TryGetValue(key, out var ttlValue)) @@ -177,10 +175,9 @@ public async Task GetAsync(string key) return default; } - public async Task RemoveAsync(string key, bool sendBackplaneNotification = true, Func? skipRemoveIfEqualFunc = null) + public Task RemoveAsync(string key, bool sendBackplaneNotification = true, Func? skipRemoveIfEqualFunc = null) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Remove, HzActivities.Area.HzMemoryCache, async: true, key: key); - return await RemoveItemAsync(key, CacheItemChangeType.Remove, sendBackplaneNotification, skipRemoveIfEqualFunc).ConfigureAwait(false); + return RemoveItemAsync(key, CacheItemChangeType.Remove, sendBackplaneNotification, skipRemoveIfEqualFunc); } private async Task RemoveItemAsync(string key, CacheItemChangeType changeType, bool sendNotification, Func? areEqualFunc = null) diff --git a/RedisBackedHzCache/RedisBackedHzCache.cs b/RedisBackedHzCache/RedisBackedHzCache.cs index 46128e0..fa4d56f 100644 --- a/RedisBackedHzCache/RedisBackedHzCache.cs +++ b/RedisBackedHzCache/RedisBackedHzCache.cs @@ -47,6 +47,7 @@ public RedisBackedHzCache(RedisBackedHzCacheOptions options) notificationType = options.notificationType, cleanupJobInterval = options.cleanupJobInterval, compressionThreshold = options.compressionThreshold, + logger = options.logger, valueChangeListener = (key, changeType, ttlValue, objectData, isPattern) => { using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.ValueChanged, HzActivities.Area.RedisBackedHzCache, key: key); @@ -159,37 +160,31 @@ private void RedisSet(string redisKey, byte[] objectData, TTLValue ttlValue) public void RemoveByPattern(string pattern, bool sendNotification = true) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.RemoveByPattern, HzActivities.Area.RedisBackedHzCache, pattern: pattern,sendNotification:sendNotification); hzCache.RemoveByPattern(pattern, sendNotification); } public void EvictExpired() { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.EvictExpired, HzActivities.Area.RedisBackedHzCache); hzCache.EvictExpired(); } public void Clear() { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Clear, HzActivities.Area.RedisBackedHzCache); hzCache.Clear(); } public bool Remove(string key, bool sendBackplaneNotification, Func skipRemoveIfEqualFunc = null) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Remove, HzActivities.Area.RedisBackedHzCache, key:key); return hzCache.Remove(key, sendBackplaneNotification, skipRemoveIfEqualFunc); } public CacheStatistics GetStatistics() { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetStatistics, HzActivities.Area.RedisBackedHzCache); return hzCache.GetStatistics(); } public T Get(string key) - - { + { using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Get, HzActivities.Area.RedisBackedHzCache, key: key); var value = hzCache.Get(key); if (value == null && options.useRedisAs2ndLevelCache) @@ -216,19 +211,16 @@ private RedisValue GetRedisValue(string key) public void Set(string key, T value) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Set, HzActivities.Area.RedisBackedHzCache, key: key); hzCache.Set(key, value); } public void Set(string key, T value, TimeSpan ttl) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Set, HzActivities.Area.RedisBackedHzCache, key: key); hzCache.Set(key, value, ttl); } public T GetOrSet(string key, Func valueFactory, TimeSpan ttl, long maxMsToWaitForFactory = 10000) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSet, HzActivities.Area.RedisBackedHzCache, key: key); return hzCache.GetOrSet(key, valueFactory, ttl, maxMsToWaitForFactory); } @@ -292,7 +284,6 @@ private RedisValue[] RedisBatchResult(RedisKey[] redisKeyList) public bool Remove(string key) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Remove, HzActivities.Area.RedisBackedHzCache, key: key); return hzCache.Remove(key); } diff --git a/RedisBackedHzCache/RedisBackedHzCacheAsync.cs b/RedisBackedHzCache/RedisBackedHzCacheAsync.cs index ffaf163..df01f56 100644 --- a/RedisBackedHzCache/RedisBackedHzCacheAsync.cs +++ b/RedisBackedHzCache/RedisBackedHzCacheAsync.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Reactive.Joins; using System.Text; using System.Threading.Tasks; using HzCache.Diagnostics; @@ -13,10 +12,9 @@ namespace HzCache { public partial class RedisBackedHzCache { - public async Task RemoveByPatternAsync(string pattern, bool sendNotification = true) + public Task RemoveByPatternAsync(string pattern, bool sendNotification = true) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.RemoveByPattern, HzActivities.Area.RedisBackedHzCache,async:true, pattern: pattern,sendNotification:sendNotification); - await hzCache.RemoveByPatternAsync(pattern, sendNotification).ConfigureAwait(false); + return hzCache.RemoveByPatternAsync(pattern, sendNotification); } public async Task GetAsync(string key) @@ -48,32 +46,29 @@ private async Task GetRedisValueAsync(string key) return await redisDb.StringGetAsync(GetRedisKey(key)).ConfigureAwait(false); } - public async Task SetAsync(string key, T value) + public Task SetAsync(string key, T value) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Set, HzActivities.Area.RedisBackedHzCache, async: true, key: key); - await hzCache.SetAsync(key, value).ConfigureAwait(false); + return hzCache.SetAsync(key, value); } - public async Task SetAsync(string key, T value, TimeSpan ttl) + public Task SetAsync(string key, T value, TimeSpan ttl) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Set, HzActivities.Area.RedisBackedHzCache, async: true, key: key); - await hzCache.SetAsync(key, value, ttl).ConfigureAwait(false); + return hzCache.SetAsync(key, value, ttl); } - public async Task GetOrSetAsync(string key, Func> valueFactory, TimeSpan ttl, long maxMsToWaitForFactory = 10000) + public Task GetOrSetAsync(string key, Func> valueFactory, TimeSpan ttl, long maxMsToWaitForFactory = 10000) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSet, HzActivities.Area.RedisBackedHzCache, async: true, key: key); - return await hzCache.GetOrSetAsync(key, valueFactory, ttl, maxMsToWaitForFactory).ConfigureAwait(false); + return hzCache.GetOrSetAsync(key, valueFactory, ttl, maxMsToWaitForFactory); } - public async Task> GetOrSetBatchAsync(IList keys, Func, Task>>> valueFactory) + public Task> GetOrSetBatchAsync(IList keys, Func, Task>>> valueFactory) { - return await GetOrSetBatchAsync(keys, valueFactory, options.defaultTTL).ConfigureAwait(false); + return GetOrSetBatchAsync(keys, valueFactory, options.defaultTTL); } public async Task> GetOrSetBatchAsync(IList keys, Func, Task>>> valueFactory, TimeSpan ttl) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSetBatch, HzActivities.Area.RedisBackedHzCache, async: true, key: string.Join(",",keys??new List())); + using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.GetOrSetBatch, HzActivities.Area.RedisBackedHzCache, async: true, key: string.Join(",", keys ?? new List())); Func, Task>>> redisFactory = async idList => { // Create a list of redis keys from the list of cache keys @@ -124,16 +119,14 @@ private Task RedisBatchResultAsync(RedisKey[] redisKeyList) return redisDb.StringGetAsync(redisKeyList); } - public async Task ClearAsync() + public Task ClearAsync() { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Clear, HzActivities.Area.RedisBackedHzCache, async: true); - await hzCache.ClearAsync().ConfigureAwait(false); + return hzCache.ClearAsync(); } - public async Task RemoveAsync(string key) + public Task RemoveAsync(string key) { - using var activity = HzActivities.Source.StartActivityWithCommonTags(HzActivities.Names.Remove, HzActivities.Area.RedisBackedHzCache, async: true, key: key); - return await hzCache.RemoveAsync(key).ConfigureAwait(false); + return hzCache.RemoveAsync(key); } } } diff --git a/UnitTests/IntegrationTests.cs b/UnitTests/IntegrationTests.cs index fc75b18..33d8cb4 100644 --- a/UnitTests/IntegrationTests.cs +++ b/UnitTests/IntegrationTests.cs @@ -43,15 +43,17 @@ public LargeMocko(string key, long numOfItems) [TestClass] public class IntegrationTests { + private const string ConnectionString = "localhost:6379"; + [TestMethod] [TestCategory("Integration")] public async Task TestRedisBackplaneInvalidation() { var c1 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c1" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1" }); await Task.Delay(200); var c2 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c2" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c2" }); Console.WriteLine("Adding 1 to c1"); await c1.SetAsync("1", new Mocko(1)); @@ -86,11 +88,11 @@ public async Task TestLargeObjects() var logger = factory.CreateLogger(); - var redis = ConnectionMultiplexer.Connect("localhost"); + var redis = ConnectionMultiplexer.Connect(ConnectionString); var c1 = new RedisBackedHzCache( new RedisBackedHzCacheOptions { - redisConnectionString = "localhost", + redisConnectionString = ConnectionString, applicationCachePrefix = "largeobjectstest", instanceId = "c1", useRedisAs2ndLevelCache = true, @@ -101,7 +103,7 @@ public async Task TestLargeObjects() var c2 = new RedisBackedHzCache( new RedisBackedHzCacheOptions { - redisConnectionString = "localhost", + redisConnectionString = ConnectionString, applicationCachePrefix = "largeobjectstest", instanceId = "c2", useRedisAs2ndLevelCache = true, @@ -171,11 +173,11 @@ public async Task TestLargeObjectsWithCompression() var logger = factory.CreateLogger(); - var redis = ConnectionMultiplexer.Connect("localhost"); + var redis = ConnectionMultiplexer.Connect(ConnectionString); var c1 = new RedisBackedHzCache( new RedisBackedHzCacheOptions { - redisConnectionString = "localhost", + redisConnectionString = ConnectionString, applicationCachePrefix = "largeobjectstest_compression", instanceId = "c1", useRedisAs2ndLevelCache = true, @@ -187,7 +189,7 @@ public async Task TestLargeObjectsWithCompression() var c2 = new RedisBackedHzCache( new RedisBackedHzCacheOptions { - redisConnectionString = "localhost", + redisConnectionString = ConnectionString, applicationCachePrefix = "largeobjectstest_compression", instanceId = "c2", useRedisAs2ndLevelCache = true, @@ -242,12 +244,12 @@ public async Task TestLargeObjectsWithCompression() [TestCategory("Integration")] public async Task TestRedisClear() { - var redis = ConnectionMultiplexer.Connect("localhost"); + var redis = ConnectionMultiplexer.Connect(ConnectionString); var c1 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c1" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1" }); await Task.Delay(200); var c2 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c2" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c2" }); Console.WriteLine("Adding 1 to c1"); await c1.SetAsync("1", new Mocko(1)); @@ -270,10 +272,10 @@ public async Task TestRedisClear() public async Task TestRedisGet() { var c1 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c1", useRedisAs2ndLevelCache = true }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1", useRedisAs2ndLevelCache = true }); await Task.Delay(200); var c2 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c2", useRedisAs2ndLevelCache = true }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c2", useRedisAs2ndLevelCache = true }); Console.WriteLine("Adding 1 to c1"); await c1.SetAsync("1", new Mocko(10)); @@ -287,10 +289,10 @@ public async Task TestRedisGet() public async Task TestRedisGetOrSet() { var c1 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c1", useRedisAs2ndLevelCache = true }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1", useRedisAs2ndLevelCache = true }); await Task.Delay(200); var c2 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c2", useRedisAs2ndLevelCache = true }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c2", useRedisAs2ndLevelCache = true }); Console.WriteLine("Adding 1 to c1"); var v1 = c1.GetOrSet("1", _ => new Mocko(10), TimeSpan.FromMinutes(1)); @@ -307,12 +309,12 @@ public async Task TestRedisGetOrSet() [TestCategory("Integration")] public async Task TestRedisBackplaneDelete() { - var redis = ConnectionMultiplexer.Connect("localhost"); + var redis = ConnectionMultiplexer.Connect(ConnectionString); var c1 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c1" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1" }); await Task.Delay(200); var c2 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c2" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c2" }); Console.WriteLine("Adding 1 to c1"); await c1.SetAsync("1", new Mocko(1)); @@ -332,11 +334,11 @@ public async Task TestRedisBackplaneDelete() [TestCategory("Integration")] public async Task TestRedisBatchGet() { - var redis = ConnectionMultiplexer.Connect("localhost"); + var redis = ConnectionMultiplexer.Connect(ConnectionString); var c1 = new RedisBackedHzCache( new RedisBackedHzCacheOptions { - redisConnectionString = "localhost", + redisConnectionString = ConnectionString, applicationCachePrefix = "batch2", instanceId = "c1", useRedisAs2ndLevelCache = true, @@ -377,12 +379,12 @@ public async Task TestRedisBatchGet() [TestCategory("Integration")] public async Task TestRedisBackplaneDeleteByPattern() { - var redis = ConnectionMultiplexer.Connect("localhost"); + var redis = ConnectionMultiplexer.Connect(ConnectionString); var c1 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c1" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c1" }); await Task.Delay(200); var c2 = new RedisBackedHzCache( - new RedisBackedHzCacheOptions { redisConnectionString = "localhost", applicationCachePrefix = "test", instanceId = "c2" }); + new RedisBackedHzCacheOptions { redisConnectionString = ConnectionString, applicationCachePrefix = "test", instanceId = "c2" }); await c1.SetAsync("11", new Mocko(11)); await c1.SetAsync("12", new Mocko(12)); @@ -414,10 +416,10 @@ public async Task TestRedisBackplaneDeleteByPattern() public async Task TestDistributedInvalidationPerformance() { var iterations = 500000.0d; - var redis = ConnectionMultiplexer.Connect("localhost"); + var redis = ConnectionMultiplexer.Connect(ConnectionString); var c1 = new RedisBackedHzCache(new RedisBackedHzCacheOptions { - redisConnectionString = "localhost", + redisConnectionString = ConnectionString, applicationCachePrefix = "test", defaultTTL = TimeSpan.FromSeconds(Math.Max(iterations / 10000, 20)), notificationType = NotificationType.Async, diff --git a/UnitTests/UnitTests.cs b/UnitTests/UnitTests.cs index 08d6b06..cf69049 100644 --- a/UnitTests/UnitTests.cs +++ b/UnitTests/UnitTests.cs @@ -25,7 +25,6 @@ public async Task TestValueChangeNotification() { var addOrUpdates = 0; var removals = 0; - var expires = 0; var cache = new HzMemoryCache( new HzCacheOptions { @@ -40,7 +39,7 @@ public async Task TestValueChangeNotification() break; case CacheItemChangeType.Expire: - expires++; + // Expire should no longer send a notification break; case CacheItemChangeType.Remove: @@ -59,8 +58,6 @@ public async Task TestValueChangeNotification() Assert.AreEqual(2, removals); cache.GetOrSet("m", _ => new MockObject(1), TimeSpan.FromMilliseconds(100)); Assert.AreEqual(3, addOrUpdates); - await Task.Delay(200); - Assert.AreEqual(1, expires); } [TestMethod] diff --git a/UnitTests/UnitTestsAsync.cs b/UnitTests/UnitTestsAsync.cs index 0a60eb7..e08ede8 100644 --- a/UnitTests/UnitTestsAsync.cs +++ b/UnitTests/UnitTestsAsync.cs @@ -11,7 +11,6 @@ public async Task TestValueChangeNotificationAsync() { var addOrUpdates = 0; var removals = 0; - var expires = 0; var cache = new HzMemoryCache( new HzCacheOptions { @@ -25,7 +24,7 @@ public async Task TestValueChangeNotificationAsync() addOrUpdates++; break; case CacheItemChangeType.Expire: - expires++; + // Expire should no longer send a notification break; case CacheItemChangeType.Remove: removals++; @@ -41,10 +40,8 @@ public async Task TestValueChangeNotificationAsync() Assert.AreEqual(1, removals); await cache.RemoveAsync("mock2"); Assert.AreEqual(2, removals); - await cache.GetOrSetAsync("m", async _ => Task.FromResult(new MockObject(1)), TimeSpan.FromMilliseconds(100)); + await cache.GetOrSetAsync("m", _ => Task.FromResult(new MockObject(1)), TimeSpan.FromMilliseconds(100)); Assert.AreEqual(3, addOrUpdates); - await Task.Delay(200); - Assert.AreEqual(1, expires); } [TestMethod] diff --git a/hzcache.sln b/hzcache.sln index 40e93b3..ae3c0bf 100644 --- a/hzcache.sln +++ b/hzcache.sln @@ -13,6 +13,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedisBackedHzCache", "Redis EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedisIDistributedCache", "RedisIDistributedCache\RedisIDistributedCache.csproj", "{F91CB554-BF50-49BB-898E-809DAF3E3382}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" + ProjectSection(SolutionItems) = preProject + CHANGELOG.md = CHANGELOG.md + README.md = README.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU