DistributedLock.Core 1.0.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package DistributedLock.Core --version 1.0.3
NuGet\Install-Package DistributedLock.Core -Version 1.0.3
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DistributedLock.Core" Version="1.0.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DistributedLock.Core --version 1.0.3
#r "nuget: DistributedLock.Core, 1.0.3"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DistributedLock.Core as a Cake Addin
#addin nuget:?package=DistributedLock.Core&version=1.0.3

// Install DistributedLock.Core as a Cake Tool
#tool nuget:?package=DistributedLock.Core&version=1.0.3

DistributedLock

DistributedLock is a .NET library that provides robust and easy-to-use distributed mutexes, reader-writer locks, and semaphores based on a variety of underlying technologies.

With DistributedLock, synchronizing access to a region of code across multiple applications/machines is as simple as:

await using (await myDistributedLock.AcquireAsync())
{
	// I hold the lock here
}

Implementations

DistributedLock contains implementations based on various technologies; you can install implementation packages individually or just install the DistributedLock NuGet package NuGet Status, an "umbrella" package which includes all implementations as dependencies. Note that each package is versioned independently according to SemVer.

The DistributedLock.Core NuGet Status package contains common code and abstractions and is referenced by all implementations.

Synchronization primitives

  • Locks: provide exclusive access to a region of code
  • Reader-writer locks: a lock with multiple levels of access. The lock can be held concurrently either by any number of readers or by a single writer.
  • Semaphores: similar to a lock, but can be held by up to N users concurrently instead of just one.

While all implementations support locks, the other primitives are only supported by some implementations. See the implementation-specific documentation pages for details.

Basic usage

Names

Because distributed locks (and other distributed synchronization primitives) are not isolated to a single process, their identity is based on their name which is provided through the constructor. Different underlying technologies have different restrictions on name format; however, DistributedLock largely allows you to ignore these by escaping/hashing names that would otherwise be invalid.

Acquire

All synchronization primitives support the same basic access pattern. The Acquire method returns a "handle" object that represents holding the lock. When the handle is disposed, the lock is released:

var myDistributedLock = new SqlDistributedLock(name, connectionString); // e. g. if we are using SQL Server
using (myDistributedLock.Acquire())
{
	// we hold the lock here
} // implicit Dispose() call from using block releases it here

TryAcquire

While Acquire will block until the lock is available, there is also a TryAcquire variant which returns null if the lock could not be acquired (due to being held elsewhere):

using (var handle = myDistributedLock.TryAcquire())
{
	if (handle != null)
	{
		// we acquired the lock :-)
	}
	else
	{
		// someone else has it :-(
	}
}

async support

async versions of both of these methods are also supported. These are preferred when you are writing async code since they will not consume a thread while waiting for the lock. If you are using C#8 or higher, you can also dispose of handles asynchronously:

Timeouts

await using (await myDistributedLock.AcquireAsync()) { ... }

Additionally, all of these methods support an optional timeout parameter. timeout determines how long Acquire will wait before failing with a TimeoutException and how long TryAcquire will wait before returning null. The default timeout for Acquire is Timeout.InfiniteTimeSpan while for TryAcquire the default timeout is TimeSpan.Zero.

Cancellation

Finally, the methods take an optional CancellationToken parameter, which allows for the acquire operation to be interrupted via cancellation. Note that this won't cancel the hold on the lock once the acquire succeeds.

Providers

For applications that use dependency injection, DistributedLock's provider make it easy to separate out the specification of a lock's (or other primitive's) name from its other settings (such as a database connection string). For example in an ASP.NET Core app you might do:

// in your Startup.cs:
services.AddSingleton<IDistributedLockProvider>(_ => new PostgresDistributedSynchronizationProvider(myConnectionString));
services.AddTransient<SomeService>();

// in SomeService.cs
public class SomeService
{
	private readonly IDistributedLockProvider _synchronizationProvider;

	public SomeService(IDistributedLockProvider synchronizationProvider)
	{
		this._synchronizationProvider = synchronizationProvider;
	}
	
	public void InitializeUserAccount(int id)
	{
		// use the provider to construct a lock
		var @lock = this._synchronizationProvider.CreateLock($"UserAccount{id}");
		using (@lock.Acquire())
		{
			// do stuff
		}
		
		// ALTERNATIVELY, for common use-cases extension methods allow this to be done with a single call
		using (this._synchronizationProvider.AcquireLock($"UserAccount{id}"))
		{
			// do stuff
		}
	}
}

Other topics

Contributing

Contributions are welcome! If you are interested in contributing towards a new or existing issue, please let me know via comments on the issue so that I can help you get started and avoid wasted effort on your part.

Release notes

  • 2.2.0
    • Added MySQL/MariaDB-based implementation (#95, DistributedLock.MySql 1.0.0)
  • 2.1.0
    • Added ZooKeeper-based implementation (#41, DistributedLock.ZooKeeper 1.0.0)
  • 2.0.2
    • Fixed bug where HandleLostToken would hang when accessed on a SqlServer or Postgres lock handle that used keepalive (#85, DistributedLock.Core 1.0.1)
    • Fixed bug where broken database connections could result in future lock attempts failing when using SqlServer or Postgres locks with multiplexing (#83, DistributedLock.Core 1.0.1)
    • Updated Npgsql dependency to 5.x to take advantage of various bugfixes (#61, DistributedLock.Postgres 1.0.1)
  • 2.0.1
    • Fixed Redis lock behavior when using a database with WithKeyPrefix (#66, DistributedLock.Redis 1.0.1). Thanks @skomis-mm for contributing!
  • 2.0.0 (see also Migrating from 1.x to 2.x)
    • Revamped package structure so that DistributedLock is now an umbrella package and each implementation technology has its own package (BREAKING CHANGE)
    • Added Postgresql-based locking (#56, DistributedLock.Postgres 1.0.0)
    • Added Redis-based locking (#24, DistributedLock.Redis 1.0.0)
    • Added Azure blob-based locking (#42, DistributedLock.Azure 1.0.0)
    • Added file-based locking (#28, DistributedLock.FileSystem 1.0.0)
    • Added provider classes for improved IOC integration (#13)
    • Added strong naming to assemblies. Thanks @pedropaulovc for contributing! (#47, BREAKING CHANGE)
    • Made lock handles implement IAsyncDisposable in addition to IDisposable #20, BREAKING CHANGE)
    • Exposed implementation-agnostic interfaces (e. g. IDistributedLock) for all synchronization primitives (#10)
    • Added HandleLostToken API for tracking if a lock's underlying connection dies (#6, BREAKING CHANGE)
    • Added SourceLink support (#57)
    • Removed GetSafeName API in favor of safe naming by default (BREAKING CHANGE)
    • Renamed "SystemDistributedLock" to "EventWaitHandleDistributedLock" (DistributedLock.WaitHandles 1.0.0)
    • Stopped supporting net45 (BREAKING CHANGE)
    • Removed DbConnection and DbTransaction constructors form SqlDistributedLock, leaving the constructors that take IDbConnection/IDbTransaction (#35, BREAKING CHANGE)
    • Changed methods returning Task<IDisposable> to instead return ValueTask, making it so that using (@lock.AcquireAsync()) { ... } without an await` no longer compiles (#34, BREAKING CHANGE)
    • Changed UpgradeableLockHandle.UpgradeToWriteLock to return void (#33, BREAKING CHANGE)
    • Switched to Microsoft.Data.SqlClient by default for all target frameworks (BREAKING CHANGE)
    • Changed all locking implementations to be non-reentrant (BREAKING CHANGE)
  • 1.5.0
    • Added cross-platform support via Microsoft.Data.SqlClient (#25). This feature is available for .NET Standard >= 2.0. Thanks to @alesebi91 for helping with the implementation and testing!
    • Added C#8 nullable annotations (#31)
    • Fixed minor bug in connection multiplexing which could lead to more lock contention (#32)
  • 1.4.0
    • Added a SQL-based distributed semaphore (#7)
    • Fix bug where SqlDistributedLockConnectionStrategy.Azure would leak connections, relying on GC to reclaim them (#14). Thanks zavalita1 for investigating this issue!
    • Throw a specific exception type (DeadlockException) rather than the generic InvalidOperationException when a deadlock is detected (#11)
  • 1.3.1 Minor fix to avoid "leaking" isolation level changes in transaction-based locks (#8). Also switched to the VS2017 project file format
  • 1.3.0 Added an Azure connection strategy to keep lock connections from becoming idle and being reclaimed by Azure's connection governor (#5)
  • 1.2.0
    • Added a SQL-based distributed reader-writer lock
    • .NET Core support via .NET Standard
    • Changed the default locking scope for SQL distributed lock to be a connection rather than a transaction, avoiding cases where long-running transactions can block backups
    • Allowed for customization of the SQL distributed lock connection strategy when connecting via a connection string
    • Added a new connection strategy which allows for multiplexing multiple held locks onto one connection
    • Added IDbConnection/IDbTransaction constructors (#3)
  • 1.1.0 Added support for SQL distributed locks scoped to existing connections/transactions
  • 1.0.1 Minor fix when using infinite timeouts
  • 1.0.0 Initial release
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (31)

Showing the top 5 NuGet packages that depend on DistributedLock.Core:

Package Downloads
DistributedLock.Redis

Provides distributed locking primitives based on Redis

DistributedLock.FileSystem

Provides a distributed lock implementation based on file locks

DistributedLock.SqlServer

Provides a distributed lock implementation based on SQL Server

DistributedLock.Postgres

Provides a distributed lock implementation based on Postgresql

Elsa.Abstractions

Elsa is a set of workflow libraries and tools that enable lean and mean workflowing capabilities in any .NET Core application. This package provides abstractions and models that are used by Elsa.Core and other related packages. You don't need to reference this package separately if you reference any other Elsa package.

GitHub repositories (6)

Showing the top 5 popular GitHub repositories that depend on DistributedLock.Core:

Repository Stars
abpframework/abp
Open Source Web Application Framework for ASP.NET Core. Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET and the ASP.NET Core platforms. Provides the fundamental infrastructure, production-ready startup templates, application modules, UI themes, tooling, guides and documentation.
fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat
可能是全网最完整的 C# 版微信 SDK,封装全部已知的微信 API,包含微信公众平台(订阅号+服务号+小程序+小游戏+小商店+视频号)、微信开放平台、微信商户平台(微信支付+微企付)、企业微信、微信广告平台、微信智能对话开放平台等模块,可跨平台。持续随官方更新,欢迎 Star/Fork/PR。QQ 交流群 875580418【满】、930461548。
masastack/MASA.Framework
Provide open, community driven reusable components for building modern applications. These components will be used by the MASA Stack and MASA Labs projects.
ikyriak/IdempotentAPI
A .NET library that handles the HTTP write operations (POST and PATCH) that can affect only once for the given request data and idempotency-key by using an ASP.NET Core attribute (filter).
junkai-li/NetCoreKevin
基于NET6搭建跨平台DDD-微服务-WebApi架构支持:IDS4单点登录、多缓存、自动任务、分布式、多租户、日志、授权和鉴权、CAP集成事件、SignalR、领域事件、单元测试
Version Downloads Last updated
1.0.6 2,499 3/26/2024
1.0.6-alpha01 6,424 9/11/2022
1.0.5 4,985,018 7/9/2022
1.0.5-alpha001 2,197 7/6/2022
1.0.4 3,757,808 12/17/2021
1.0.4-beta001 797 12/13/2021
1.0.3 339,774 10/2/2021
1.0.3-rc01 990 8/25/2021
1.0.2 1,403,593 6/18/2021
1.0.1 1,399,044 4/24/2021
1.0.0 2,829,045 1/14/2021
1.0.0-alpha02 1,928 12/23/2020
1.0.0-alpha01 4,120 8/28/2020