diff --git a/KeySmith.Tests/IntegrationMemoTests.cs b/KeySmith.Tests/IntegrationMemoTests.cs index 18b1b31..a79a2c2 100644 --- a/KeySmith.Tests/IntegrationMemoTests.cs +++ b/KeySmith.Tests/IntegrationMemoTests.cs @@ -20,7 +20,7 @@ public async Task SimpleScenario() var service = provider.GetRequiredService(); var root = Guid.NewGuid().ToString().Substring(0, 8); - var memoKey = new MemoKey(root, "name", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(500)); + var memoKey = new MemoKey(root, "name", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); var db = provider.GetRequiredService().GetDatabase(); await ResetKeys(db, memoKey); @@ -49,31 +49,37 @@ public async Task SimpleFailScenario() var service = provider.GetRequiredService(); var root = Guid.NewGuid().ToString().Substring(0, 8); - var memoKey = new MemoKey(root, "name", TimeSpan.FromSeconds(100), TimeSpan.FromSeconds(500)); + var memoKey = new MemoKey(root, "name", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2)); var db = provider.GetRequiredService().GetDatabase(); await ResetKeys(db, memoKey); try { - RedisValue answer = "answer"; - var failedFirstTask = service.MemoLockAsync(memoKey, c => + try { - throw new NullReferenceException("oups"); - }, CancellationToken.None); - var succesfullSecondTask = WaitBeforeStart(service.MemoLockAsync(memoKey, c => Task.FromResult(answer), CancellationToken.None), 100); + await service.MemoLockAsync(memoKey, c => throw new NullReferenceException("oups"), CancellationToken.None); + + throw new Exception("Nothing was thrown"); + } + catch (NullReferenceException) + { + } + catch (GenerationException)// we actually get it from redis before we had time to clean the setup. + { + } try { - Task.WaitAll(failedFirstTask, succesfullSecondTask); + RedisValue answer = "answer"; + await service.MemoLockAsync(memoKey, c => Task.FromResult(answer), CancellationToken.None); + + throw new Exception("Nothing was thrown"); } - catch (AggregateException e) + catch (GenerationException) { - Assert.Equal(2, e.InnerExceptions.Count); - Assert.Single(e.InnerExceptions.OfType()); - Assert.Single(e.InnerExceptions.OfType()); } - Assert.False(await db.KeyExistsAsync(memoKey.GetValueKey()));//value is in redis + Assert.False(await db.KeyExistsAsync(memoKey.GetValueKey())); Assert.True(await db.KeyExistsAsync(memoKey.GetErrorKey())); } finally @@ -82,12 +88,6 @@ public async Task SimpleFailScenario() } } - private async Task WaitBeforeStart(Task t, int ms) - { - await Task.Delay(ms); - await t; - } - [Fact] public async Task ConcurrencyScenario() { @@ -98,7 +98,7 @@ public async Task ConcurrencyScenario() var service = provider.GetRequiredService(); var root = Guid.NewGuid().ToString().Substring(0, 8); - var memoKey = new MemoKey(root, "name", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(500)); + var memoKey = new MemoKey(root, "name", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); var db = provider.GetRequiredService().GetDatabase(); @@ -131,8 +131,8 @@ public async Task ConcurrencyScenario() Assert.Equal(42, answer); } - Assert.True(await db.KeyExistsAsync(memoKey.GetValueKey()));//value is in redis Assert.False(await db.KeyExistsAsync(memoKey.GetErrorKey())); + Assert.True(await db.KeyExistsAsync(memoKey.GetValueKey())); } finally { diff --git a/KeySmith.Tests/LockContextTests.cs b/KeySmith.Tests/LockContextTests.cs index 6eee7d7..b698f06 100644 --- a/KeySmith.Tests/LockContextTests.cs +++ b/KeySmith.Tests/LockContextTests.cs @@ -41,6 +41,15 @@ public void HandlerTests(string message, object initialState) } break; case State.WithKey: + if (context.Identifier == message) + { + Assert.Equal(State.WithKey, context.State); + } + else + { + Assert.Equal(State.Done, context.State); + } + break; case State.Done: Assert.Equal(State.Done, context.State); break; diff --git a/KeySmith/MemoLockService.cs b/KeySmith/MemoLockService.cs index 1ce84d4..327fa41 100644 --- a/KeySmith/MemoLockService.cs +++ b/KeySmith/MemoLockService.cs @@ -77,7 +77,16 @@ private async Task MemoLockWithoutSubscriptionAsync(MemoKey key, Fun try { - return await _lockService.LockAsync(key.GetLockKey(), c => LockedCallback(key, generator, c), cancellationToken).ConfigureAwait(false); + return await _lockService.LockAsync(key.GetLockKey(), async c => + { + //in case we missed the publication + var result = await TryGetCachedValue(key).ConfigureAwait(false); + if (result != null) + { + return result.Value; + } + return await LockedCallback(key, generator, c).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); } catch (TaskCanceledException) { @@ -119,7 +128,7 @@ private Action GetHandler(CancellationTokenSource sour } else { - task.SetResult(v); + task.TrySetResult(v); } try