From 22d7408c09ed09184fa2276083550bdc409de328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 Oct 2021 09:20:27 +0300 Subject: [PATCH] Introduce Volo.Abp.DistributedLocking.Abstractions package #10032 --- framework/Volo.Abp.sln | 16 ++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 ++++++++ ...Abp.DistributedLocking.Abstractions.csproj | 21 ++++++ ...AbpDistributedLockingAbstractionsModule.cs | 9 +++ .../DistributedLocking/IAbpDistributedLock.cs | 26 +++++++ .../IAbpDistributedLockHandle.cs | 9 +++ .../LocalAbpDistributedLock.cs | 28 +++++++ .../LocalAbpDistributedLockHandle.cs | 21 ++++++ .../Volo.Abp.DistributedLocking.csproj | 2 +- .../AbpDistributedLockingModule.cs | 3 + ...stributedLocking.Abstractions.Tests.csproj | 18 +++++ ...pDistributedLockingAbstractionsTestBase.cs | 12 +++ ...istributedLockingAbstractionsTestModule.cs | 15 ++++ .../LocalDistributedLock_Tests.cs | 73 +++++++++++++++++++ nupkg/common.ps1 | 1 + 16 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xml create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xsd create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsModule.cs create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLock.cs create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLockHandle.cs create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs create mode 100644 framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs create mode 100644 framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo.Abp.DistributedLocking.Abstractions.Tests.csproj create mode 100644 framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestBase.cs create mode 100644 framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestModule.cs create mode 100644 framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/LocalDistributedLock_Tests.cs diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 309be85ea1..1a4229ea34 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -372,6 +372,7 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AzureServiceBus", "src\Volo.Abp.AzureServiceBus\Volo.Abp.AzureServiceBus.csproj", "{808EC18E-C8CC-4F5C-82B6-984EADBBF85D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Azure", "src\Volo.Abp.EventBus.Azure\Volo.Abp.EventBus.Azure.csproj", "{FB27F78E-F10E-4810-9B8E-BCD67DCFC8A2}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Authorization.Abstractions", "src\Volo.Abp.Authorization.Abstractions\Volo.Abp.Authorization.Abstractions.csproj", "{87B0C2A8-FE95-4779-8B9C-2181AA52B3FA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Core", "src\Volo.Abp.TextTemplating.Core\Volo.Abp.TextTemplating.Core.csproj", "{184E859A-282D-44D7-B8E9-FEA874644013}" @@ -393,10 +394,15 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Boxes", "src\Volo.Abp.EventBus.Boxes\Volo.Abp.EventBus.Boxes.csproj", "{6E289F31-7924-418B-9DAC-62A7CFADF916}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.DistributedLocking", "src\Volo.Abp.DistributedLocking\Volo.Abp.DistributedLocking.csproj", "{9A7EEA08-15BE-476D-8168-53039867038E}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Auditing.Contracts", "src\Volo.Abp.Auditing.Contracts\Volo.Abp.Auditing.Contracts.csproj", "{508B6355-AD28-4E60-8549-266D21DBF2CF}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Client.Web", "src\Volo.Abp.Http.Client.Web\Volo.Abp.Http.Client.Web.csproj", "{F7407459-8AFA-45E4-83E9-9BB01412CC08}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.DistributedLocking.Abstractions", "src\Volo.Abp.DistributedLocking.Abstractions\Volo.Abp.DistributedLocking.Abstractions.csproj", "{CA805B77-D50C-431F-B3CB-1111C9C6E807}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.DistributedLocking.Abstractions.Tests", "test\Volo.Abp.DistributedLocking.Abstractions.Tests\Volo.Abp.DistributedLocking.Abstractions.Tests.csproj", "{C4F54FB5-C828-414D-BA03-E8E7A10C784D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1187,6 +1193,14 @@ Global {F7407459-8AFA-45E4-83E9-9BB01412CC08}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7407459-8AFA-45E4-83E9-9BB01412CC08}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7407459-8AFA-45E4-83E9-9BB01412CC08}.Release|Any CPU.Build.0 = Release|Any CPU + {CA805B77-D50C-431F-B3CB-1111C9C6E807}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA805B77-D50C-431F-B3CB-1111C9C6E807}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA805B77-D50C-431F-B3CB-1111C9C6E807}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA805B77-D50C-431F-B3CB-1111C9C6E807}.Release|Any CPU.Build.0 = Release|Any CPU + {C4F54FB5-C828-414D-BA03-E8E7A10C784D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4F54FB5-C828-414D-BA03-E8E7A10C784D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4F54FB5-C828-414D-BA03-E8E7A10C784D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4F54FB5-C828-414D-BA03-E8E7A10C784D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1388,6 +1402,8 @@ Global {9A7EEA08-15BE-476D-8168-53039867038E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {508B6355-AD28-4E60-8549-266D21DBF2CF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {F7407459-8AFA-45E4-83E9-9BB01412CC08} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {CA805B77-D50C-431F-B3CB-1111C9C6E807} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {C4F54FB5-C828-414D-BA03-E8E7A10C784D} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xml b/framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xsd b/framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj new file mode 100644 index 0000000000..ab828ee9d3 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.0 + Volo.Abp.DistributedLocking.Abstractions + Volo.Abp.DistributedLocking.Abstractions + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsModule.cs b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsModule.cs new file mode 100644 index 0000000000..9c3832e49b --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsModule.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.DistributedLocking +{ + public class AbpDistributedLockingAbstractionsModule : AbpModule + { + + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLock.cs b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLock.cs new file mode 100644 index 0000000000..15f8921577 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLock.cs @@ -0,0 +1,26 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using JetBrains.Annotations; + +namespace Volo.Abp.DistributedLocking +{ + public interface IAbpDistributedLock + { + /// + /// Tries to acquire a named lock. + /// Returns a disposable object to release the lock. + /// It is suggested to use this method within a using block. + /// Returns null if the lock could not be handled. + /// + /// The name of the lock + /// Timeout value + /// Cancellation token + [ItemCanBeNull] + Task TryAcquireAsync( + string name, + TimeSpan timeout = default, + CancellationToken cancellationToken = default + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLockHandle.cs b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLockHandle.cs new file mode 100644 index 0000000000..baac5296c7 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/IAbpDistributedLockHandle.cs @@ -0,0 +1,9 @@ +using System; + +namespace Volo.Abp.DistributedLocking +{ + public interface IAbpDistributedLockHandle : IAsyncDisposable + { + + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs new file mode 100644 index 0000000000..7a34106b0d --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.DistributedLocking +{ + public class LocalAbpDistributedLock : IAbpDistributedLock, ISingletonDependency + { + private readonly ConcurrentDictionary _localSyncObjects = new(); + + public async Task TryAcquireAsync( + string name, + TimeSpan timeout = default, + CancellationToken cancellationToken = default) + { + var semaphore = _localSyncObjects.GetOrAdd(name, _ => new SemaphoreSlim(1, 1)); + + if (!await semaphore.WaitAsync(timeout, cancellationToken)) + { + return null; + } + + return new LocalAbpDistributedLockHandle(semaphore); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs new file mode 100644 index 0000000000..da12739311 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs @@ -0,0 +1,21 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Volo.Abp.DistributedLocking +{ + public class LocalAbpDistributedLockHandle : IAbpDistributedLockHandle + { + private readonly SemaphoreSlim _semaphore; + + public LocalAbpDistributedLockHandle(SemaphoreSlim semaphore) + { + _semaphore = semaphore; + } + + public ValueTask DisposeAsync() + { + _semaphore.Release(); + return default; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj b/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj index c4b590412d..17ad2f02a4 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj +++ b/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs index 877ac54244..3bfdbbf3f3 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs +++ b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs @@ -2,6 +2,9 @@ namespace Volo.Abp.DistributedLocking { + [DependsOn( + typeof(AbpDistributedLockingAbstractionsModule) + )] public class AbpDistributedLockingModule : AbpModule { diff --git a/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo.Abp.DistributedLocking.Abstractions.Tests.csproj b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo.Abp.DistributedLocking.Abstractions.Tests.csproj new file mode 100644 index 0000000000..8194846f0c --- /dev/null +++ b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo.Abp.DistributedLocking.Abstractions.Tests.csproj @@ -0,0 +1,18 @@ + + + + + + net6.0 + true + + + + + + + + + + + diff --git a/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestBase.cs b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestBase.cs new file mode 100644 index 0000000000..074bd342d2 --- /dev/null +++ b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Testing; + +namespace Volo.Abp.DistributedLocking +{ + public class AbpDistributedLockingAbstractionsTestBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } +} diff --git a/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestModule.cs b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestModule.cs new file mode 100644 index 0000000000..cfc9278335 --- /dev/null +++ b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/AbpDistributedLockingAbstractionsTestModule.cs @@ -0,0 +1,15 @@ +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace Volo.Abp.DistributedLocking +{ + [DependsOn( + typeof(AbpTestBaseModule), + typeof(AbpDistributedLockingAbstractionsModule), + typeof(AbpAutofacModule) + )] + public class AbpDistributedLockingAbstractionsTestModule : AbpModule + { + + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/LocalDistributedLock_Tests.cs b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/LocalDistributedLock_Tests.cs new file mode 100644 index 0000000000..ce7fda009d --- /dev/null +++ b/framework/test/Volo.Abp.DistributedLocking.Abstractions.Tests/Volo/Abp/DistributedLocking/LocalDistributedLock_Tests.cs @@ -0,0 +1,73 @@ +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.Abp.DistributedLocking +{ + public class LocalDistributedLock_Tests : AbpDistributedLockingAbstractionsTestBase + { + private readonly IAbpDistributedLock _distributedLock; + + public LocalDistributedLock_Tests() + { + _distributedLock = GetRequiredService(); + } + + [Fact] + public void Should_Be_Instance_Of_LocalAbpDistributedLock() + { + _distributedLock.ShouldBeOfType(); + } + + [Fact] + public async Task Should_Lock_With_TryAcquire() + { + await using (var handle = await _distributedLock.TryAcquireAsync("lock1")) + { + handle.ShouldNotBeNull(); + } + } + + [Fact] + public async Task Should_Not_Acquire_If_Already_Locked() + { + await using (var handle = await _distributedLock.TryAcquireAsync("lock1")) + { + handle.ShouldNotBeNull(); + + await Task.Run(async () => + { + await using (var handle2 = await _distributedLock.TryAcquireAsync("lock1")) + { + handle2.ShouldBeNull(); + } + }); + } + + await Task.Run(async () => + { + await using (var handle = await _distributedLock.TryAcquireAsync("lock1")) + { + handle.ShouldNotBeNull(); + } + }); + } + + [Fact] + public async Task Should_Obtain_Multiple_Locks() + { + await using (var handle = await _distributedLock.TryAcquireAsync("lock1")) + { + handle.ShouldNotBeNull(); + + await Task.Run(async () => + { + await using (var handle2 = await _distributedLock.TryAcquireAsync("lock2")) + { + handle2.ShouldNotBeNull(); + } + }); + } + } + } +} \ No newline at end of file diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 7d48c1ac1d..9fae28d572 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -92,6 +92,7 @@ $projects = ( "framework/src/Volo.Abp.Ddd.Application", "framework/src/Volo.Abp.Ddd.Application.Contracts", "framework/src/Volo.Abp.Ddd.Domain", + "framework/src/Volo.Abp.DistributedLocking.Abstractions", "framework/src/Volo.Abp.DistributedLocking", "framework/src/Volo.Abp.Emailing", "framework/src/Volo.Abp.EntityFrameworkCore",