-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Milestone
Description
It is currently not an issue for DisableConcurrentExecutionAttribute, since it wraps a parent task (which Hangfire runs synchronously), but it can become one in the future.
Consider the following test:
private async Task AsyncChildTask()
{
using (var connection = ConnectionUtils.CreateConnection())
{
var storage = CreateStorage(connection);
using (var @lock = new SqlServerDistributedLock(storage, "test", _timeout))
{
var AcquiredLocksField = typeof(SqlServerDistributedLock)
.GetField("AcquiredLocks", BindingFlags.Static | BindingFlags.NonPublic);
var AcquiredLocks = (ThreadLocal<Dictionary<string, int>>)AcquiredLocksField.GetValue(null);
Assert.True(AcquiredLocks.Value.ContainsKey("test"));
await Task.Yield();
Assert.True(AcquiredLocks.Value.ContainsKey("test"), "Lock is not owned"); // False!
}
});
}
[Fact]
public void ParentTaskCallingAsyncChild()
{
Task.WaitAll(AsyncChildTask());
}It will fail the second assertion, because task may continue on different thread, so using ThreadLocal<> is incorrect for storing owned locks. You should use AsyncLocal<> instead (CallContext on older frameworks).