mirror of https://github.com/abpframework/abp.git
46 changed files with 440 additions and 135 deletions
@ -1,2 +0,0 @@ |
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
|||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary> |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -1,4 +1,4 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.DistributedLocking |
|||
{ |
|||
public class AbpDistributedLockingAbstractionsModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.DistributedLocking |
|||
{ |
|||
public interface IAbpDistributedLock |
|||
{ |
|||
/// <summary>
|
|||
/// 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.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the lock</param>
|
|||
/// <param name="timeout">Timeout value</param>
|
|||
/// <param name="cancellationToken">Cancellation token</param>
|
|||
[ItemCanBeNull] |
|||
Task<IAbpDistributedLockHandle> TryAcquireAsync( |
|||
[NotNull] string name, |
|||
TimeSpan timeout = default, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.DistributedLocking |
|||
{ |
|||
public interface IAbpDistributedLockHandle : IAsyncDisposable |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
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<string, SemaphoreSlim> _localSyncObjects = new(); |
|||
|
|||
public async Task<IAbpDistributedLockHandle> TryAcquireAsync( |
|||
string name, |
|||
TimeSpan timeout = default, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
|
|||
var semaphore = _localSyncObjects.GetOrAdd(name, _ => new SemaphoreSlim(1, 1)); |
|||
|
|||
if (!await semaphore.WaitAsync(timeout, cancellationToken)) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return new LocalAbpDistributedLockHandle(semaphore); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using Medallion.Threading; |
|||
|
|||
namespace Volo.Abp.DistributedLocking |
|||
{ |
|||
public static class AbpDistributedLockHandleExtensions |
|||
{ |
|||
public static IDistributedSynchronizationHandle ToDistributedSynchronizationHandle( |
|||
this IAbpDistributedLockHandle handle) |
|||
{ |
|||
return handle.As<MedallionAbpDistributedLockHandle>().Handle; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Medallion.Threading; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.DistributedLocking |
|||
{ |
|||
[Dependency(ReplaceServices = true)] |
|||
public class MedallionAbpDistributedLock : IAbpDistributedLock, ITransientDependency |
|||
{ |
|||
protected IDistributedLockProvider DistributedLockProvider { get; } |
|||
|
|||
public MedallionAbpDistributedLock(IDistributedLockProvider distributedLockProvider) |
|||
{ |
|||
DistributedLockProvider = distributedLockProvider; |
|||
} |
|||
|
|||
public async Task<IAbpDistributedLockHandle> TryAcquireAsync( |
|||
string name, |
|||
TimeSpan timeout = default, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
|
|||
var handle = await DistributedLockProvider.TryAcquireLockAsync(name, timeout, cancellationToken); |
|||
if (handle == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return new MedallionAbpDistributedLockHandle(handle); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System.Threading.Tasks; |
|||
using Medallion.Threading; |
|||
|
|||
namespace Volo.Abp.DistributedLocking |
|||
{ |
|||
public class MedallionAbpDistributedLockHandle : IAbpDistributedLockHandle |
|||
{ |
|||
public IDistributedSynchronizationHandle Handle { get; } |
|||
|
|||
public MedallionAbpDistributedLockHandle(IDistributedSynchronizationHandle handle) |
|||
{ |
|||
Handle = handle; |
|||
} |
|||
|
|||
public ValueTask DisposeAsync() |
|||
{ |
|||
return Handle.DisposeAsync(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,3 +0,0 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -1,20 +0,0 @@ |
|||
using Volo.Abp.BackgroundWorkers; |
|||
using Volo.Abp.DistributedLocking; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.EventBus.Boxes |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpEventBusModule), |
|||
typeof(AbpBackgroundWorkersModule), |
|||
typeof(AbpDistributedLockingModule) |
|||
)] |
|||
public class AbpEventBusBoxesModule : AbpModule |
|||
{ |
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
context.AddBackgroundWorker<OutboxSenderManager>(); |
|||
context.AddBackgroundWorker<InboxProcessManager>(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.EventBus.Boxes |
|||
{ |
|||
internal static class TaskDelayHelper |
|||
{ |
|||
public static async Task DelayAsync(int milliseconds, CancellationToken cancellationToken = default) |
|||
{ |
|||
try |
|||
{ |
|||
await Task.Delay(milliseconds, cancellationToken); |
|||
} |
|||
catch (TaskCanceledException) |
|||
{ |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.test.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.DistributedLocking.Abstractions\Volo.Abp.DistributedLocking.Abstractions.csproj" /> |
|||
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.Testing; |
|||
|
|||
namespace Volo.Abp.DistributedLocking |
|||
{ |
|||
public class AbpDistributedLockingAbstractionsTestBase : AbpIntegratedTest<AbpDistributedLockingAbstractionsTestModule> |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
} |
|||
} |
|||
@ -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 |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -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<IAbpDistributedLock>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Be_Instance_Of_LocalAbpDistributedLock() |
|||
{ |
|||
_distributedLock.ShouldBeOfType<LocalAbpDistributedLock>(); |
|||
} |
|||
|
|||
[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(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue