Throw a specific exception for deadlocks
oliverhanappi opened this issue · 3 comments
The method SqlApplicationLock.ParseExitCode
throws an InvalidOperationException
when a deadlock is detected. It would be very useful if a specific exception would be thrown.
Hi @oliverhanappi thank you for your interest in the library.
I'm curious whether you've ever seen the deadlock exit code returned. I remember trying to force this a while back and not seeing it.
Provided we can create a test case where this is actually returned, this suggestion makes sense and would be an easy enhancement. For backwards compat, the new exception should extend InvalidOperationException
.
It is actually pretty easy. You just need to acquire multiple locks within the same connection or transaction such that two connections/transactions are waiting on each other. Here is a simple repro:
using System;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
using Medallion.Threading.Sql;
namespace SqlDistributedLockDeadlock
{
public static class Program
{
public static void Main ()
{
using (var barrier = new Barrier (2))
{
var task1 = Task.Run (() => WithTransaction((connection, transaction) =>
{
new SqlDistributedLock ("test1", transaction).Acquire();
barrier.SignalAndWait();
new SqlDistributedLock ("test2", transaction).Acquire();
}));
var task2 = Task.Run (() => WithTransaction((connection, transaction) =>
{
new SqlDistributedLock ("test2", transaction).Acquire();
barrier.SignalAndWait();
new SqlDistributedLock ("test1", transaction).Acquire();
}));
Task.WaitAll (task1, task2);
}
}
private static void WithTransaction (Action<SqlConnection, SqlTransaction> action)
{
const string connectionString = "Server=localhost;Database=Playground;Integrated Security=True";
using (var connection = new SqlConnection (connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
action.Invoke (connection, transaction);
connection.Close();
}
}
}
}
This is addressed as of version 1.4