diff --git a/src/Squidex.Infrastructure/Log/LockingLogStore.cs b/src/Squidex.Infrastructure/Log/LockingLogStore.cs index 70bd41ef0..e6b931ebf 100644 --- a/src/Squidex.Infrastructure/Log/LockingLogStore.cs +++ b/src/Squidex.Infrastructure/Log/LockingLogStore.cs @@ -7,6 +7,7 @@ using System; using System.IO; +using System.Text; using System.Threading; using System.Threading.Tasks; using Orleans; @@ -16,7 +17,8 @@ namespace Squidex.Infrastructure.Log { public sealed class LockingLogStore : ILogStore { - private static readonly TimeSpan LockWaitingTime = TimeSpan.FromMinutes(10); + private static readonly byte[] LockedText = Encoding.UTF8.GetBytes("Another process is currenty running, try it again later."); + private static readonly TimeSpan LockWaitingTime = TimeSpan.FromMinutes(1); private readonly ILogStore inner; private readonly ILockGrain lockGrain; @@ -30,12 +32,17 @@ namespace Squidex.Infrastructure.Log lockGrain = grainFactory.GetGrain(SingleGrain.Id); } - public async Task ReadLogAsync(string key, DateTime from, DateTime to, Stream stream) + public Task ReadLogAsync(string key, DateTime from, DateTime to, Stream stream) { - string releaseToken = null; + return ReadLogAsync(key, from, to, stream, LockWaitingTime); + } - using (var cts = new CancellationTokenSource(LockWaitingTime)) + public async Task ReadLogAsync(string key, DateTime from, DateTime to, Stream stream, TimeSpan lockTimeout) + { + using (var cts = new CancellationTokenSource(lockTimeout)) { + string releaseToken = null; + while (!cts.IsCancellationRequested) { releaseToken = await lockGrain.AcquireLockAsync(key); @@ -47,15 +54,22 @@ namespace Squidex.Infrastructure.Log await Task.Delay(2000); } - } - try - { - await inner.ReadLogAsync(key, from, to, stream); - } - finally - { - await lockGrain.ReleaseLockAsync(releaseToken); + if (!cts.IsCancellationRequested) + { + try + { + await inner.ReadLogAsync(key, from, to, stream); + } + finally + { + await lockGrain.ReleaseLockAsync(releaseToken); + } + } + else + { + await stream.WriteAsync(LockedText, 0, LockedText.Length); + } } } } diff --git a/tests/Squidex.Infrastructure.Tests/Log/LockingLogStoreTests.cs b/tests/Squidex.Infrastructure.Tests/Log/LockingLogStoreTests.cs index 2c0ef2c49..ae3f73854 100644 --- a/tests/Squidex.Infrastructure.Tests/Log/LockingLogStoreTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Log/LockingLogStoreTests.cs @@ -56,5 +56,32 @@ namespace Squidex.Infrastructure.Log A.CallTo(() => inner.ReadLogAsync(key, dateFrom, dateTo, stream)) .MustHaveHappened(); } + + [Fact] + public async Task Should_write_default_message_if_lock_could_not_be_acquired() + { + var stream = new MemoryStream(); + + var dateFrom = DateTime.Today; + var dateTo = dateFrom.AddDays(2); + + var key = "MyKey"; + + A.CallTo(() => lockGrain.AcquireLockAsync(key)) + .Returns(Task.FromResult(null)); + + await sut.ReadLogAsync(key, dateFrom, dateTo, stream, TimeSpan.FromSeconds(2)); + + A.CallTo(() => lockGrain.AcquireLockAsync(key)) + .MustHaveHappened(); + + A.CallTo(() => lockGrain.ReleaseLockAsync(A.Ignored)) + .MustNotHaveHappened(); + + A.CallTo(() => inner.ReadLogAsync(A.Ignored, A.Ignored, A.Ignored, A.Ignored)) + .MustNotHaveHappened(); + + Assert.True(stream.Length > 0); + } } }