mirror of https://github.com/abpframework/abp.git
1 changed files with 67 additions and 40 deletions
@ -1,77 +1,104 @@ |
|||||
# Distributed Locking |
# Distributed Locking |
||||
Distributed locking is very useful to manage many applications that trying to access the same resource. |
Distributed locking is technique to manage many applications that trying to access the same resource. |
||||
The main purpose is to allow only one of many applications to access the same resource at the same time. |
The main purpose is to allow only one of many applications to access the same resource at the same time. |
||||
Otherwise accessing the same object from various applications may corrupt the value of resources. |
Otherwise accessing the same object from various applications may corrupt the value of resources. |
||||
On this occasion, distributed locking protects the correct value throughout the applications. |
|
||||
|
|
||||
> To use in ABP, you should download the below NuGet package or can open any command apps and run the below command. |
> ABP's current distributed locking implementation is based on the [DistributedLock](https://github.com/madelson/DistributedLock) library. |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
You can open a command-line terminal and type the following command to install the [Volo.Abp.DistributedLocking](https://www.nuget.org/packages/Volo.Abp.DistributedLocking) package it into your project: |
||||
|
|
||||
````powershell |
````powershell |
||||
abp add-package Volo.Abp.DistributedLocking |
abp add-package Volo.Abp.DistributedLocking |
||||
```` |
```` |
||||
|
|
||||
````csharp |
This package provides the necessary API to use the distributed locking system, however, you should configure a provider before using it. |
||||
using Volo.Abp.DistributedLocking; |
|
||||
namespace AbpDemo |
|
||||
{ |
|
||||
public class MyService : ITransientDependency |
|
||||
{ |
|
||||
private readonly IAbpDistributedLock _distributedLock; |
|
||||
public MyService(IAbpDistributedLock distributedLock) |
|
||||
{ |
|
||||
_distributedLock = distributedLock; |
|
||||
} |
|
||||
|
|
||||
public async Task MyMethodAsync() |
|
||||
{ |
|
||||
await using (var handle = await _distributedLock.TryAcquireAsync("NameOfLock")) |
|
||||
{ |
|
||||
if (handle != null) |
|
||||
{ |
|
||||
//your code |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
```` |
|
||||
|
|
||||
This provider contains a method named `TryAcquireAsync` and this method returns null if the lock could not be handled. |
### Configuring a provider |
||||
`name` is mandatory. It keeps the locked provider name. This name should be unique, otherwise, it will be seen as a different lock. |
|
||||
`timeout` is set as default. If it fells deadlock and doesn't work properly you can use define the time to kill it. |
|
||||
`cancellationToken` is set as default. It enables cooperative cancellation between threads, thread pool work items, or Task objects |
|
||||
|
|
||||
ABP depends on [DistributedLock.Core](https://www.nuget.org/packages/DistributedLock.Core) library which provides a distributed locking system for concurrency control in a distributed environment. There are [many distributed lock providers](https://github.com/madelson/DistributedLock#implementations) including Redis, SqlServer and ZooKeeper. You may use the one you want. ABP implements the Redis provider for you and you may customize the others yourselves. |
The [DistributedLock](https://github.com/madelson/DistributedLock) library provides [various of implementations](https://github.com/madelson/DistributedLock#implementations) for the locking, like [Redis](https://github.com/madelson/DistributedLock/blob/master/docs/DistributedLock.Redis.md) and and [ZooKeeper](https://github.com/madelson/DistributedLock/blob/master/docs/DistributedLock.ZooKeeper.md). |
||||
|
|
||||
Firstly, you should add [DistributedLock.Redis](https://www.nuget.org/packages/DistributedLock.Redis) NuGet package to your project, then add the following code into the ConfigureService method of your ABP module class. |
For example, if you want to use the [Redis provider](https://github.com/madelson/DistributedLock/blob/master/docs/DistributedLock.Redis.md), you should add [DistributedLock.Redis](https://www.nuget.org/packages/DistributedLock.Redis) NuGet package to your project, then add the following code into the `ConfigureServices` method of your ABP [module](Module-Development-Basics.md) class: |
||||
|
|
||||
````csharp |
````csharp |
||||
using Medallion.Threading; |
using Medallion.Threading; |
||||
using Medallion.Threading.Redis; |
using Medallion.Threading.Redis; |
||||
|
|
||||
namespace AbpDemo |
namespace AbpDemo |
||||
{ |
{ |
||||
public class MyModule : AbpModule |
public class MyModule : AbpModule |
||||
{ |
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
//the other configurations |
|
||||
var configuration = context.Services.GetConfiguration(); |
var configuration = context.Services.GetConfiguration(); |
||||
|
|
||||
context.Services.AddSingleton<IDistributedLockProvider>(sp => |
context.Services.AddSingleton<IDistributedLockProvider>(sp => |
||||
{ |
{ |
||||
var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); |
var connection = ConnectionMultiplexer |
||||
return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); |
.Connect(configuration["Redis:Configuration"]); |
||||
|
return new |
||||
|
RedisDistributedSynchronizationProvider(connection.GetDatabase()); |
||||
}); |
}); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
```` |
```` |
||||
|
|
||||
Also, you should add your Redis configuration in appsetting.json. |
This code gets the Redis connection string from the [configuration](Configuration.md), so you can add the following lines to your `appsettings.json` file: |
||||
You may change the structure of the JSON file but it must match with the above configuration code. |
|
||||
````json |
````json |
||||
"Redis": { |
"Redis": { |
||||
"Configuration": "127.0.0.1" |
"Configuration": "127.0.0.1" |
||||
} |
} |
||||
```` |
```` |
||||
|
|
||||
As mentioned above, this implementation is for Redis and for more detail you can visit [the GitHub site](https://github.com/madelson/DistributedLock#implementations). |
## Usage |
||||
|
|
||||
|
There are two ways to use the distributed locking API: ABP's `IAbpDistributedLock` abstraction and [DistributedLock](https://github.com/madelson/DistributedLock) library's API. |
||||
|
|
||||
|
### Using the IAbpDistributedLock service |
||||
|
|
||||
|
`IAbpDistributedLock` is a simple service provided by the ABP framework for simple usage of distributed locking. |
||||
|
|
||||
|
**Example: Using `IAbpDistributedLock.TryAcquireAsync` method** |
||||
|
|
||||
|
````csharp |
||||
|
using Volo.Abp.DistributedLocking; |
||||
|
|
||||
|
namespace AbpDemo |
||||
|
{ |
||||
|
public class MyService : ITransientDependency |
||||
|
{ |
||||
|
private readonly IAbpDistributedLock _distributedLock; |
||||
|
public MyService(IAbpDistributedLock distributedLock) |
||||
|
{ |
||||
|
_distributedLock = distributedLock; |
||||
|
} |
||||
|
|
||||
|
public async Task MyMethodAsync() |
||||
|
{ |
||||
|
await using (var handle = |
||||
|
await _distributedLock.TryAcquireAsync("MyLockName")) |
||||
|
{ |
||||
|
if (handle != null) |
||||
|
{ |
||||
|
// your code that access the shared resource |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
`TryAcquireAsync` may not acquire the lock. It returns `null` if the lock could not be acquired. In this case, you shouldn't access the resource. If the handle is not `null`, it means that you've obtained the lock and can safely access the resource. |
||||
|
|
||||
|
`TryAcquireAsync` method gets the following parameters: |
||||
|
|
||||
|
* `name` (`string`, required): Unique name of your lock. Different named locks are used to access different resources. |
||||
|
* `timeout` (`TimeSpan`): A timeout value to wait to obtain the lock. Default value is `TimeSpan.Zero`, which means it doesn't wait if the lock is already owned by another application. |
||||
|
* `cancellationToken`: A cancellation token that can be triggered later to cancel the operation. |
||||
|
|
||||
|
### Using DistributedLock library's API |
||||
|
|
||||
|
ABP's `IAbpDistributedLock` service is very limited and mainly designed to be internally used by the ABP Framework. For your own applications, you can use DistributedLock library's own API. See its [own documentation](https://github.com/madelson/DistributedLock) for details. |
||||
Loading…
Reference in new issue