Distributed Locking

Distributed locking is a technique to manage many applications that try 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. Otherwise, accessing the same object from various applications may corrupt the value of the resources.

ABP's current distributed locking implementation is based on the DistributedLock library.

Installation

You can open a command-line terminal and type the following command to install the Volo.Abp.DistributedLocking package into your project:

abp add-package Volo.Abp.DistributedLocking

This package provides the necessary API to use the distributed locking system, however, you should configure a provider before using it.

Configuring a Provider

The DistributedLock library provides various of implementations for the locking, like Redis and ZooKeeper.

For example, if you want to use the Redis provider, you should add DistributedLock.Redis NuGet package to your project, then add the following code into the ConfigureServices method of your ABP module class:

using Medallion.Threading;
using Medallion.Threading.Redis;

namespace AbpDemo
{
    [DependsOn(
            typeof(AbpDistributedLockingModule)
            //If you have the other dependencies, you should do here
    )]
    public class MyModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var configuration = context.Services.GetConfiguration();
        
            context.Services.AddSingleton<IDistributedLockProvider>(sp =>
            {
                var connection = ConnectionMultiplexer
                    .Connect(configuration["Redis:Configuration"]);
                return new 
                    RedisDistributedSynchronizationProvider(connection.GetDatabase());
            });
        }
    }
}

This code gets the Redis connection string from the configuration, so you can add the following lines to your appsettings.json file:

"Redis": {
    "Configuration": "127.0.0.1"
}

Usage

There are two ways to use the distributed locking API: ABP's IAbpDistributedLock abstraction and 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 the IAbpDistributedLock.TryAcquireAsync method

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 the DistributedLock library's own API. See its own documentation for details.

The Volo.Abp.DistributedLocking.Abstractions Package

If you are building a reusable library or an application module, then you may not want to bring an additional dependency to your module for simple applications that run as a single instance. In this case, your library can depend on the Volo.Abp.DistributedLocking.Abstractions package which defines the IAbpDistributedLock service and implements it as in-process (not distributed actually). In this way, your library can run properly (without a distributed lock provider dependency) in an application that runs as a single instance. If the application is deployed to a clustered environment, then the application developer should install a real distributed provider as explained in the Installation section.

In this document