Exception in DisposeAsync()?
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
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.