DistributedLock icon indicating copy to clipboard operation
DistributedLock copied to clipboard

Exception in DisposeAsync()?

Open viblo-majority opened this issue 6 months ago • 1 comments

We use the Sql Server implemention of DistributedLock, currently DistributedLock.SqlServer 1.0.5.

I have seen that sometimes we have exceptions when calling DisposeAsync(). In general I thought Dispose/DisposeAsync shouldn't throw, but Im not sure in this case? Is it a bug, or something I should expect?

Our usage is something like this


var cnx = await GetOpenConnection(connectionStringName);
var @lock = new SqlDistributedLock(lockName, cnx);
await using var handle = await @lock.TryAcquireAsync(expiryTime, cancellationToken);
... logic here

Then sometimes there's an exception on Dispose, with this stacktrace:

Microsoft.Data.SqlClient.SqlException (0x80131904): A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 2 - Connection was terminated)
   at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location ---
   at Medallion.Threading.Internal.Data.DatabaseCommand.ExecuteAsync[TResult](Func`3 executeAsync, Func`2 executeSync, CancellationToken cancellationToken, Boolean disallowAsyncCancellation, Boolean isConnectionMonitoringQuery) in /_/src/DistributedLock.Core/Internal/Data/DatabaseCommand.cs:line 82
   at Medallion.Threading.SqlServer.SqlApplicationLock.ExecuteReleaseCommandAsync(DatabaseConnection connection, String lockName, Boolean isTry) in /_/src/DistributedLock.SqlServer/SqlApplicationLock.cs:line 67
   at Medallion.Threading.Internal.Data.DedicatedConnectionOrTransactionDbDistributedLock.Handle`1.InnerHandle.DisposeAsync() in /_/src/DistributedLock.Core/Internal/Data/DedicatedConnectionOrTransactionDbDistributedLock.cs:line 222
   at Medallion.Threading.Internal.Data.DedicatedConnectionOrTransactionDbDistributedLock.Handle`1.InnerHandle.DisposeAsync() in /_/src/DistributedLock.Core/Internal/Data/DedicatedConnectionOrTransactionDbDistributedLock.cs:line 227

viblo-majority avatar Jun 05 '25 14:06 viblo-majority

This is by design. My concern with not doing this was that in many applications failure to release the lock is potentially very problematic; it’s something you don’t want to swallow silently.

My suggestion for the short term would be to create a local extension method on IDistributedSynchronizationHandle which wraps dispose(async) with try-catch behavior.

Long term, I’m open to discussion on this behavior. I agree that it can violate expectations.

madelson avatar Jun 27 '25 18:06 madelson