Notidar.MongoDB.Lock.Extensions 1.1.0

dotnet add package Notidar.MongoDB.Lock.Extensions --version 1.1.0                
NuGet\Install-Package Notidar.MongoDB.Lock.Extensions -Version 1.1.0                
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="Notidar.MongoDB.Lock.Extensions" Version="1.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Notidar.MongoDB.Lock.Extensions --version 1.1.0                
#r "nuget: Notidar.MongoDB.Lock.Extensions, 1.1.0"                
#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 Notidar.MongoDB.Lock.Extensions as a Cake Addin
#addin nuget:?package=Notidar.MongoDB.Lock.Extensions&version=1.1.0

// Install Notidar.MongoDB.Lock.Extensions as a Cake Tool
#tool nuget:?package=Notidar.MongoDB.Lock.Extensions&version=1.1.0                

mongo-lock

Distributed lock library for C#/.NET using MongoDB.

Notidar.MongoDB.Lock NuGet Version is a core library that provides a simple way to create distributed locks for simple apps. LockStore can be used for direct lock manipulation, while LockService provides a high level abstraction. Include extensions for creating collection and indexes.

Notidar.MongoDB.Lock.Extensions NuGet Version is a library that provides all required extensions to use the library with Microsoft.Extensions.DependencyInjection.

Features

  • Distributed locks using MongoDB
    • Exclusive locks
    • Shared locks
    • Semaphore like usage with shared locks
  • High level abstraction with LockService
  • Low level manipulation with LockStore
  • Optional MongoDB collection auto cleanup for expired locks based on TTL index
  • Flexible lock configuration with LockOptions

Usage

With IServiceCollection with high level manipulations

...
services
    .AddMongoDb(configuration.GetSection(nameof(DatabaseOptions))) // if MongoDB not registered
    .AddMongoLocks(configuration.GetSection(nameof(LockSettings))); // add all required services for locks
...

// resolve lock service
var lockService = sp.GetRequiredService<ILockService>();

await using (var sharedLock1 = await lockService.SharedLockAsync(resourceId, operationCancellationToken))
{
    // shared lock1 acquired
    await DoSomethingAsync(sharedLock1.HealthToken); // use `sharedLock1.HealthToken` to check if lock is still valid
    await using (var sharedLock2 = await lockService.SharedLockAsync(resourceId, operationCancellationToken))
    {
        // shared lock2 acquired
        await DoSomethingAsync2(sharedLock2.HealthToken); // use `sharedLock2.HealthToken` to check if lock is still valid
    }
    // shared lock2 released
}
// shared lock1 released

await using (var exclusiveLock = await lockService.ExclusiveLockAsync(resourceId, operationCancellationToken))
{
    // exclusive lock acquired
    await DoSomethingExclusivelyAsync(exclusiveLock.HealthToken); // use `exclusiveLock.HealthToken` to check if lock is still valid
}
// exclusive lock released

Simple console app with low level manipulations

var client = new MongoClient(connectionString);
var database = client.GetDatabase("cli-test");

var lockStore = new LockStore(database.GetCollection<Resource>("locks")); // Resource defined in Notidar.MongoDB.Lock.Stores
var lockService = new LockService(lockStore); // in case you need high level manipulations

// low level manipulation
var resourceResult = await lockStore.ExclusiveLockAsync("resourceId-1", "lockId-1", TimeSpan.FromSeconds(60)); // exlusive lock
if (resource?.ExclusiveLock?.LockId == "lockId-1")
{
    // exclusive locked aquired
    await lockStore.ExclusiveUnlockAsync("resourceId-1", "lockId-1"); // exlusive release
}

var resourceFirstSharedResult = await lockStore.SharedLockAsync("resourceId-1", "lockId-2", TimeSpan.FromSeconds(60));
var resourceSecondSharedResult = await lockStore.SharedLockAsync("resourceId-1", "lockId-3", TimeSpan.FromSeconds(60), sharedLockLimit: 10);
if (resourceFirstSharedResult?.SharedLocks?.Any(x => x.LockId == "lockId-2") && resourceSecondSharedResult?.SharedLocks?.Any(x => x.LockId == "lockId-3"))
{
    // both shared locked aquired
    await lockStore.SharedUnlockAsync("resourceId-1", "lockId-2"); // shared release
    await lockStore.SharedUnlockAsync("resourceId-1", "lockId-3"); // shared release
}

See samples folder for more examples.

Roadmap (Contributions are welcome)

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.

  • Add support auto cleanup for expired locks
  • Add support for infinite locks (locks that never expire)
  • Add support for optional lock re-entry
  • Add logging support
  • Add CLI for managing locks. (e.g. mongo-lock --list, mongo-lock --delete <lockId>)
  • Add support for MongoDB unlock detection. Based either MongoDB Capped Collections with signals or on MongoDB Change Streams (e.g. LockService.WaitForUnlockAsync(lockId, timeout))
  • Improve unit test coverage

License

MIT License

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 is compatible.  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 was computed.  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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.0 207 5/21/2024
1.0.0 96 5/14/2024
0.1.2 118 5/6/2024
0.0.2 120 4/29/2024
0.0.1 109 4/29/2024