Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bf67ed3
feat: Added support for MongoDB distributed locks
joesdu Oct 21, 2025
80ff241
提高封装性并优化代码可读性
joesdu Oct 21, 2025
e06c413
fix: 为 DistributedLock.MongoDB 添加 InternalsVisibleTo
joesdu Oct 21, 2025
003ce7b
fix: ci error
joesdu Oct 22, 2025
e26e3b7
add authors
joesdu Oct 22, 2025
b2cf5aa
fix: error RS0025,移除可空引用类型指令
joesdu Oct 22, 2025
b0fe2d0
docs: 添加 DistributedLock.MongoDB 完整文档并修正 README 排版与列表缩进
joesdu Oct 22, 2025
9b4ddf4
fix: ci
joesdu Oct 22, 2025
e260979
tests: 在 CombinatorialTests.cs 中添加 MongoDB 组合测试类 Core_Mongo_MongoDbSy…
joesdu Oct 23, 2025
3a28ef0
fix: ci error?
joesdu Oct 23, 2025
cd14125
style: fix code format
joesdu Oct 23, 2025
a064e4b
Merge branch 'master' into master
joesdu Nov 9, 2025
ba277b3
chore: Performance Optimization
joesdu Dec 17, 2025
e70c35c
fix: Ensure proper cancellation token usage with ConfigureAwait(false)
joesdu Dec 17, 2025
2a7ad15
Supports Fencing Token and Adaptive Backoff, enhancing robustness
joesdu Jan 5, 2026
14b924d
remove dotnet 10 the current ci does not support.
joesdu Jan 5, 2026
55c081a
feat: update docs
joesdu Jan 5, 2026
c01cc83
fix: collection name and diagnostics
joesdu Jan 7, 2026
0cb242f
fix: change CPM condition introduction
joesdu Jan 7, 2026
8adb4b9
fix: pass all tests, change collection name to `distributed.locks`
joesdu Jan 7, 2026
91b5878
fix: 更改Mongo分布式锁默认集合名为distributed.locks
joesdu Jan 7, 2026
80c0738
Apply suggestion from @Copilot
joesdu Jan 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 76 additions & 73 deletions README.md

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions docs/DistributedLock.MongoDB.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# DistributedLock.MongoDB

[Download the NuGet package](https://www.nuget.org/packages/DistributedLock.MongoDB) [![NuGet Status](http://img.shields.io/nuget/v/DistributedLock.MongoDB.svg?style=flat)](https://www.nuget.org/packages/DistributedLock.MongoDB/)

The DistributedLock.MongoDB package offers distributed locks based on [MongoDB](https://www.mongodb.com/). For example:

```C#
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("myDatabase");
var @lock = new MongoDistributedLock("MyLockName", database);
await using (await @lock.AcquireAsync())
{
// I have the lock
}
```

## APIs

- The `MongoDistributedLock` class implements the `IDistributedLock` interface.
- The `MongoDistributedSynchronizationProvider` class implements the `IDistributedLockProvider` interface.

## Implementation notes

MongoDB-based locks use MongoDB's document upsert and update operations to implement distributed locking. The implementation works as follows:

1. **Acquisition**: Attempts to insert or update a document with the lock key and a unique lock ID.
2. **Extension**: Automatically extends the lock expiry while held to prevent timeout.
3. **Release**: Deletes the lock document when disposed.
4. **Expiry**: Locks automatically expire if not extended, allowing recovery from crashed processes.

MongoDB locks can be constructed with an `IMongoDatabase` and an optional collection name. If no collection name is specified, locks will be stored in a collection named `"DistributedLocks"`. The collection will automatically have an index created on the `expiresAt` field for efficient queries.

When using the provider pattern, you can create multiple locks with different names from the same provider:

```C#
var client = new MongoClient(connectionString);
var database = client.GetDatabase("myDatabase");
var provider = new MongoDistributedSynchronizationProvider(database);

var lock1 = provider.CreateLock("lock1");
var lock2 = provider.CreateLock("lock2");

await using (await lock1.AcquireAsync())
{
// Do work with lock1
}
```

**NOTE**: Lock extension happens automatically in the background while the lock is held. If lock extension fails (for example, due to network issues), the `HandleLostToken` will be signaled to notify you that the lock may have been lost.

## Options

In addition to specifying the name and database, several tuning options are available:

- `Expiry` determines how long the lock will be initially claimed for. Because of automatic extension, locks can be held for longer than this value. Defaults to 30 seconds.
- `ExtensionCadence` determines how frequently the hold on the lock will be renewed to the full `Expiry`. Defaults to 1/3 of `Expiry` (approximately 10 seconds when using the default expiry).
- `BusyWaitSleepTime` specifies a range of times that the implementation will sleep between attempts to acquire a lock that is currently held by someone else. A random time in the range will be chosen for each sleep. If you expect contention, lowering these values may increase responsiveness (how quickly a lock detects that it can now be taken) but will increase the number of calls made to MongoDB. Raising the values will have the reverse effects. Defaults to a range of 10ms to 800ms.

Example of using options:

```C#
var @lock = new MongoDistributedLock(
"MyLockName",
database,
options => options
.Expiry(TimeSpan.FromSeconds(30))
.ExtensionCadence(TimeSpan.FromSeconds(10))
.BusyWaitSleepTime(
min: TimeSpan.FromMilliseconds(10),
max: TimeSpan.FromMilliseconds(800))
);
```

You can also specify a custom collection name:

```C#
var @lock = new MongoDistributedLock("MyLockName", database, "MyCustomLocks");
```

## Stale lock cleanup

Stale locks from crashed processes will automatically expire based on the `Expiry` setting. MongoDB's built-in TTL index support ensures that expired lock documents are cleaned up automatically by the database. This means that if a process crashes while holding a lock, the lock will become available again after the expiry time has elapsed.
2 changes: 2 additions & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageVersion Include="MongoDB.Driver" Version="3.5.2" />
<PackageVersion Include="Nullable" Version="1.3.1" Condition="'$(TargetFramework)' != 'netstandard2.1'" />
<PackageVersion Include="MySqlConnector" Version="2.3.5" />
<PackageVersion Include="NUnit.Analyzers" Version="4.1.0" />
Expand All @@ -21,6 +22,7 @@
<PackageVersion Include="MedallionShell.StrongName" Version="1.6.2" />
<PackageVersion Include="System.Data.SqlClient" Version="4.8.6" />
<PackageVersion Include="Moq" Version="4.20.70" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="10.0.1" Condition="'$(TargetFramework)' == 'netstandard2.1' OR '$(TargetFramework)' == 'net472'" />
<PackageVersion Include="System.Threading.AccessControl" Version="8.0.0" Condition="'$(TargetFramework)' != 'net462'" />
<PackageVersion Include="ZooKeeperNetEx" Version="3.4.12.4" />
<PackageVersion Include="IsExternalInit" Version="1.0.3" />
Expand Down
32 changes: 14 additions & 18 deletions src/DistributedLock.Azure/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,15 +470,6 @@
"resolved": "4.5.1",
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
},
"System.Diagnostics.DiagnosticSource": {
"type": "Transitive",
"resolved": "6.0.1",
"contentHash": "KiLYDu2k2J82Q9BJpWiuQqCkFjRBWVq4jDzKKWawVi9KWzyD0XG3cmfX0vqTQlL14Wi9EufJrbL0+KCLTbqWiQ==",
"dependencies": {
"System.Memory": "4.5.4",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.IO.Hashing": {
"type": "Transitive",
"resolved": "6.0.0",
Expand All @@ -490,13 +481,8 @@
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.4",
"contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.4.0",
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
"resolved": "4.6.3",
"contentHash": "qdcDOgnFZY40+Q9876JUHnlHu7bosOHX8XISRoH94fwk6hgaeQGSgfZd8srWRZNt5bV9ZW2TljcegDNxsf+96A=="
},
"System.Memory.Data": {
"type": "Transitive",
Expand All @@ -514,8 +500,8 @@
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
"resolved": "6.1.2",
"contentHash": "2hBr6zdbIBTDE3EhK7NSVNdX58uTK6iHW/P/Axmm9sl1xoGSLqDvMtpecn226TNwHByFokYwJmt/aQQNlO5CRw=="
},
"System.Text.Encodings.Web": {
"type": "Transitive",
Expand Down Expand Up @@ -546,6 +532,16 @@
},
"distributedlock.core": {
"type": "Project"
},
"System.Diagnostics.DiagnosticSource": {
"type": "CentralTransitive",
"requested": "[10.0.1, )",
"resolved": "10.0.1",
"contentHash": "wVYO4/71Pk177uQ3TG8ZQFS3Pnmr98cF9pYxnpuIb/bMnbEWsdZZoLU/euv29mfSi2/Iuypj0TRUchPk7aqBGg==",
"dependencies": {
"System.Memory": "4.6.3",
"System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/DistributedLock.Core/AssemblyAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@
[assembly: InternalsVisibleTo("DistributedLock.ZooKeeper, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fd3af56ccc8ed94fffe25bfd651e6a5674f8f20a76d37de800dd0f7380e04f0fde2da6fa200380b14fe398605b6f470c87e5e0a0bf39ae871f07536a4994aa7a0057c4d3bcedc8fef3eecb0c88c2024a1b3289305c2393acd9fb9f9a42d0bd7826738ce864d507575ea3a1fe1746ab19823303269f79379d767949807f494be8")]
[assembly: InternalsVisibleTo("DistributedLock.MySql, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fd3af56ccc8ed94fffe25bfd651e6a5674f8f20a76d37de800dd0f7380e04f0fde2da6fa200380b14fe398605b6f470c87e5e0a0bf39ae871f07536a4994aa7a0057c4d3bcedc8fef3eecb0c88c2024a1b3289305c2393acd9fb9f9a42d0bd7826738ce864d507575ea3a1fe1746ab19823303269f79379d767949807f494be8")]
[assembly: InternalsVisibleTo("DistributedLock.Oracle, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fd3af56ccc8ed94fffe25bfd651e6a5674f8f20a76d37de800dd0f7380e04f0fde2da6fa200380b14fe398605b6f470c87e5e0a0bf39ae871f07536a4994aa7a0057c4d3bcedc8fef3eecb0c88c2024a1b3289305c2393acd9fb9f9a42d0bd7826738ce864d507575ea3a1fe1746ab19823303269f79379d767949807f494be8")]
[assembly: InternalsVisibleTo("DistributedLock.MongoDB, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fd3af56ccc8ed94fffe25bfd651e6a5674f8f20a76d37de800dd0f7380e04f0fde2da6fa200380b14fe398605b6f470c87e5e0a0bf39ae871f07536a4994aa7a0057c4d3bcedc8fef3eecb0c88c2024a1b3289305c2393acd9fb9f9a42d0bd7826738ce864d507575ea3a1fe1746ab19823303269f79379d767949807f494be8")]
#endif
30 changes: 3 additions & 27 deletions src/DistributedLock.Core/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@
"System.Threading.Tasks.Extensions": "4.5.4"
}
},
"Microsoft.CodeAnalysis.PublicApiAnalyzers": {
"type": "Direct",
"requested": "[3.3.4, )",
"resolved": "3.3.4",
"contentHash": "kNLTfXtXUWDHVt5iaPkkiPuyHYlMgLI6SOFT4w88bfeI2vqSeGgHunFkdvlaCM8RDfcY0t2+jnesQtidRJJ/DA=="
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
Expand Down Expand Up @@ -81,12 +75,6 @@
"System.Threading.Tasks.Extensions": "4.5.4"
}
},
"Microsoft.CodeAnalysis.PublicApiAnalyzers": {
"type": "Direct",
"requested": "[3.3.4, )",
"resolved": "3.3.4",
"contentHash": "kNLTfXtXUWDHVt5iaPkkiPuyHYlMgLI6SOFT4w88bfeI2vqSeGgHunFkdvlaCM8RDfcY0t2+jnesQtidRJJ/DA=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
Expand Down Expand Up @@ -136,12 +124,6 @@
}
},
".NETStandard,Version=v2.1": {
"Microsoft.CodeAnalysis.PublicApiAnalyzers": {
"type": "Direct",
"requested": "[3.3.4, )",
"resolved": "3.3.4",
"contentHash": "kNLTfXtXUWDHVt5iaPkkiPuyHYlMgLI6SOFT4w88bfeI2vqSeGgHunFkdvlaCM8RDfcY0t2+jnesQtidRJJ/DA=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
Expand All @@ -164,17 +146,11 @@
}
},
"net8.0": {
"Microsoft.CodeAnalysis.PublicApiAnalyzers": {
"type": "Direct",
"requested": "[3.3.4, )",
"resolved": "3.3.4",
"contentHash": "kNLTfXtXUWDHVt5iaPkkiPuyHYlMgLI6SOFT4w88bfeI2vqSeGgHunFkdvlaCM8RDfcY0t2+jnesQtidRJJ/DA=="
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.4, )",
"resolved": "8.0.4",
"contentHash": "PZb5nfQ+U19nhnmnR9T1jw+LTmozhuG2eeuzuW5A7DqxD/UXW2ucjmNJqnqOuh8rdPzM3MQXoF8AfFCedJdCUw=="
"requested": "[8.0.22, )",
"resolved": "8.0.22",
"contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
Expand Down
6 changes: 6 additions & 0 deletions src/DistributedLock.MongoDB/AssemblyAttributes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using System.Runtime.CompilerServices;

[assembly:
InternalsVisibleTo(
"DistributedLock.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fd3af56ccc8ed94fffe25bfd651e6a5674f8f20a76d37de800dd0f7380e04f0fde2da6fa200380b14fe398605b6f470c87e5e0a0bf39ae871f07536a4994aa7a0057c4d3bcedc8fef3eecb0c88c2024a1b3289305c2393acd9fb9f9a42d0bd7826738ce864d507575ea3a1fe1746ab19823303269f79379d767949807f494be8")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
66 changes: 66 additions & 0 deletions src/DistributedLock.MongoDB/DistributedLock.MongoDB.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.1;net8.0;net472;</TargetFrameworks>
<RootNamespace>Medallion.Threading.MongoDB</RootNamespace>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<WarningLevel>4</WarningLevel>
<LangVersion>Latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<PropertyGroup>
<Version>1.3.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<Authors>Michael Adelson, joesdu</Authors>
<Description>Provides a distributed lock implementation based on MongoDB</Description>
<Copyright>Copyright © 2020 Michael Adelson</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageTags>distributed lock async mongodb</PackageTags>
<PackageProjectUrl>https://github.com/madelson/DistributedLock</PackageProjectUrl>
<RepositoryUrl>https://github.com/madelson/DistributedLock</RepositoryUrl>
<FileVersion>1.0.0.0</FileVersion>
<PackageReleaseNotes>See https://github.com/madelson/DistributedLock#release-notes</PackageReleaseNotes>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\DistributedLock.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<Optimize>True</Optimize>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<TreatSpecificWarningsAsErrors />
<!-- see https://github.com/dotnet/sdk/issues/2679 -->
<DebugType>embedded</DebugType>
<!-- see https://mitchelsellers.com/blog/article/net-5-deterministic-builds-source-linking -->
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<Optimize>False</Optimize>
<NoWarn>1591</NoWarn>
<DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1' OR '$(TargetFramework)' == 'net472'">
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="MongoDB.Driver" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DistributedLock.Core\DistributedLock.Core.csproj" />
</ItemGroup>

<ItemGroup>
<Using Remove="System.Net.Http" />
</ItemGroup>

<Import Project="..\FixDistributedLockCoreDependencyVersion.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Medallion.Threading.Internal;

namespace Medallion.Threading.MongoDB;

public partial class MongoDistributedLock
{
// AUTO-GENERATED

IDistributedSynchronizationHandle? IDistributedLock.TryAcquire(TimeSpan timeout, CancellationToken cancellationToken) =>
this.TryAcquire(timeout, cancellationToken);
IDistributedSynchronizationHandle IDistributedLock.Acquire(TimeSpan? timeout, CancellationToken cancellationToken) =>
this.Acquire(timeout, cancellationToken);
ValueTask<IDistributedSynchronizationHandle?> IDistributedLock.TryAcquireAsync(TimeSpan timeout, CancellationToken cancellationToken) =>
this.TryAcquireAsync(timeout, cancellationToken).Convert(To<IDistributedSynchronizationHandle?>.ValueTask);
ValueTask<IDistributedSynchronizationHandle> IDistributedLock.AcquireAsync(TimeSpan? timeout, CancellationToken cancellationToken) =>
this.AcquireAsync(timeout, cancellationToken).Convert(To<IDistributedSynchronizationHandle>.ValueTask);

/// <summary>
/// Attempts to acquire the lock synchronously. Usage:
/// <code>
/// using (var handle = myLock.TryAcquire(...))
/// {
/// if (handle != null) { /* we have the lock! */ }
/// }
/// // dispose releases the lock if we took it
/// </code>
/// </summary>
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to 0</param>
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
/// <returns>A <see cref="MongoDistributedLockHandle"/> which can be used to release the lock or null on failure</returns>
public MongoDistributedLockHandle? TryAcquire(TimeSpan timeout = default, CancellationToken cancellationToken = default) =>
DistributedLockHelpers.TryAcquire(this, timeout, cancellationToken);

/// <summary>
/// Acquires the lock synchronously, failing with <see cref="TimeoutException"/> if the attempt times out. Usage:
/// <code>
/// using (myLock.Acquire(...))
/// {
/// /* we have the lock! */
/// }
/// // dispose releases the lock
/// </code>
/// </summary>
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to <see cref="Timeout.InfiniteTimeSpan"/></param>
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
/// <returns>A <see cref="MongoDistributedLockHandle"/> which can be used to release the lock</returns>
public MongoDistributedLockHandle Acquire(TimeSpan? timeout = null, CancellationToken cancellationToken = default) =>
DistributedLockHelpers.Acquire(this, timeout, cancellationToken);

/// <summary>
/// Attempts to acquire the lock asynchronously. Usage:
/// <code>
/// await using (var handle = await myLock.TryAcquireAsync(...))
/// {
/// if (handle != null) { /* we have the lock! */ }
/// }
/// // dispose releases the lock if we took it
/// </code>
/// </summary>
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to 0</param>
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
/// <returns>A <see cref="MongoDistributedLockHandle"/> which can be used to release the lock or null on failure</returns>
public ValueTask<MongoDistributedLockHandle?> TryAcquireAsync(TimeSpan timeout = default, CancellationToken cancellationToken = default) =>
this.As<IInternalDistributedLock<MongoDistributedLockHandle>>().InternalTryAcquireAsync(timeout, cancellationToken);

/// <summary>
/// Acquires the lock asynchronously, failing with <see cref="TimeoutException"/> if the attempt times out. Usage:
/// <code>
/// await using (await myLock.AcquireAsync(...))
/// {
/// /* we have the lock! */
/// }
/// // dispose releases the lock
/// </code>
/// </summary>
/// <param name="timeout">How long to wait before giving up on the acquisition attempt. Defaults to <see cref="Timeout.InfiniteTimeSpan"/></param>
/// <param name="cancellationToken">Specifies a token by which the wait can be canceled</param>
/// <returns>A <see cref="MongoDistributedLockHandle"/> which can be used to release the lock</returns>
public ValueTask<MongoDistributedLockHandle> AcquireAsync(TimeSpan? timeout = null, CancellationToken cancellationToken = default) =>
DistributedLockHelpers.AcquireAsync(this, timeout, cancellationToken);
}
Loading