Skip to content

Commit 93d7789

Browse files
committed
Added Timespan for easily tracking lock time.
1 parent 75fd5bf commit 93d7789

4 files changed

Lines changed: 34 additions & 4 deletions

File tree

SqlAppLockHelper.Common/SqlAppLockHelper.Common.csproj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
<Authors>BBernard / CajunCoding</Authors>
77
<Company>CajunCoding</Company>
88
<Product>SqlAppLockHelper</Product>
9-
<Description>The Common libraries for SqlAppLockHelper; You should install SqlAppLockHelper.SystemData or SqlAppLockHelper.MicrosoftData depending on which SqlClient liberaries are in use in your project.</Description>
9+
<Description>The Common libraries for SqlAppLockHelper; a library for easily using Sql Server built in support for robust distributed mutex / applicaiton locking capabilities. You should install SqlAppLockHelper.SystemData or SqlAppLockHelper.MicrosoftData depending on which SqlClient liberaries are in use in your project.</Description>
1010
<Copyright>Copyright © 2020</Copyright>
1111
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1212
<PackageProjectUrl>https://github.com/cajuncoding/SqlAppLockHelper</PackageProjectUrl>
1313
<RepositoryUrl>https://github.com/cajuncoding/SqlAppLockHelper</RepositoryUrl>
1414
<PackageTags>sp_getapplock, sp_releaseapplock, distributed-locking, distributed-lock-algorithm, app-locking, application-locking, sql, sqlserver, sql-server, sqlclient, locking, application-lock, application-lock-system, transactional-outbox-pattern, azurefunctions, azure-functions, serverless</PackageTags>
15-
<PackageReleaseNotes>Initial release of Async/Sync support for System.Data &amp; Microsoft.Data namespace.</PackageReleaseNotes>
15+
<PackageReleaseNotes>- Improve stability for Disposing, removing unnecessary exception warnings as locks are released when Connections are disposed/closed. Added explicit Release() &amp; ReleaseAsync() methods, updated tests, and added Timespan for easily tracking lock time.
16+
17+
Prior Release Notes:
18+
- Initial release of Async/Sync support for System.Data &amp; Microsoft.Data namespace.</PackageReleaseNotes>
19+
<Version>1.0.1</Version>
1620
</PropertyGroup>
1721

1822
</Project>

SqlAppLockHelper.Common/SqlServerAppLock.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Text;
45
using System.Threading.Tasks;
56

@@ -11,13 +12,16 @@ public class SqlServerAppLock : IDisposable, IAsyncDisposable
1112
// namespaces, reducing duplication.
1213
private Func<ValueTask> _releaseActionAsync = null;
1314
private Action _releaseAction = null;
15+
private Stopwatch _lockTimer = new Stopwatch();
1416

1517
public string LockName { get; }
1618

1719
public SqlServerAppLockScope LockScope { get; }
1820

1921
public SqlServerAppLockAcquisitionResult LockAcquisitionResult { get; }
2022

23+
public TimeSpan LockElapsedTime => _lockTimer.Elapsed;
24+
2125
public SqlServerAppLock(
2226
string lockName,
2327
SqlServerAppLockScope scope,
@@ -32,6 +36,10 @@ public SqlServerAppLock(
3236
LockScope = scope;
3337
LockAcquisitionResult = lockAcquisitionResult;
3438

39+
//Start the Lock Timer ONLY if Lock was Acquired!
40+
if(this.IsLockAcquired)
41+
_lockTimer.Start();
42+
3543
//Initialize Sync & Async callbacks for Disposal!
3644
//NOTE: Using Delegates here allows this class to be independent of Microsoft.Data/System.Data
3745
// namespaces, reducing duplication.
@@ -56,6 +64,8 @@ public async Task ReleaseAsync()
5664
{
5765
await _releaseActionAsync.Invoke();
5866
_releaseActionAsync = null;
67+
68+
_lockTimer.Stop();
5969
}
6070
}
6171

@@ -66,8 +76,12 @@ public async Task ReleaseAsync()
6676
/// </summary>
6777
public void Release()
6878
{
69-
_releaseAction?.Invoke();
70-
_releaseAction = null;
79+
if (_releaseAction != null)
80+
{
81+
_releaseAction.Invoke();
82+
_releaseAction = null;
83+
_lockTimer.Stop();
84+
}
7185
}
7286

7387
/// <summary>
@@ -83,6 +97,7 @@ public void Dispose()
8397
Release();
8498
}
8599

100+
_lockTimer.Stop();
86101
IsDisposed = true;
87102
}
88103

@@ -99,6 +114,7 @@ public async ValueTask DisposeAsync()
99114
await ReleaseAsync();
100115
}
101116

117+
_lockTimer.Stop();
102118
IsDisposed = true;
103119
}
104120
}

SqlAppLockHelper.Tests/MicrosoftDataConnectionAppLockTests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public async Task TestAsyncConnectionAppLockAcquisitionExceptionsDisabled()
4040
Assert.AreEqual(appLockFailWhileLocked.LockAcquisitionResult, SqlServerAppLockAcquisitionResult.FailedDueToTimeout);
4141
Assert.IsFalse(string.IsNullOrWhiteSpace(appLockFailWhileLocked.LockName));
4242

43+
//Check App Lock Elapsed Timers!
44+
Assert.IsTrue(appLock.LockElapsedTime.TotalMilliseconds > 0);
45+
Assert.IsTrue(appLockFailWhileLocked.LockElapsedTime.TotalMilliseconds == 0);
46+
4347
//Force Release the Lock!
4448
await appLock.DisposeAsync();
4549

@@ -56,6 +60,7 @@ public async Task TestAsyncConnectionAppLockAcquisitionExceptionsDisabled()
5660
Assert.IsNotNull(appLockAfterRelease);
5761
Assert.AreEqual(appLockAfterRelease.LockAcquisitionResult, SqlServerAppLockAcquisitionResult.AcquiredImmediately);
5862
Assert.IsFalse(string.IsNullOrWhiteSpace(appLockAfterRelease.LockName));
63+
Assert.IsTrue(appLockAfterRelease.LockElapsedTime.TotalMilliseconds > 0);
5964
}
6065

6166
[TestMethod]

SqlAppLockHelper.Tests/SystemDataConnectionAppLockTests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public async Task TestAsyncConnectionAppLockAcquisitionExceptionsDisabled()
4040
Assert.AreEqual(appLockFailWhileLocked.LockAcquisitionResult, SqlServerAppLockAcquisitionResult.FailedDueToTimeout);
4141
Assert.IsFalse(string.IsNullOrWhiteSpace(appLockFailWhileLocked.LockName));
4242

43+
//Check App Lock Elapsed Timers!
44+
Assert.IsTrue(appLock.LockElapsedTime.TotalMilliseconds > 0);
45+
Assert.IsTrue(appLockFailWhileLocked.LockElapsedTime.TotalMilliseconds == 0);
46+
4347
//Force Release the Lock!
4448
await appLock.DisposeAsync();
4549

@@ -56,6 +60,7 @@ public async Task TestAsyncConnectionAppLockAcquisitionExceptionsDisabled()
5660
Assert.IsNotNull(appLockAfterRelease);
5761
Assert.AreEqual(appLockAfterRelease.LockAcquisitionResult, SqlServerAppLockAcquisitionResult.AcquiredImmediately);
5862
Assert.IsFalse(string.IsNullOrWhiteSpace(appLockAfterRelease.LockName));
63+
Assert.IsTrue(appLockAfterRelease.LockElapsedTime.TotalMilliseconds > 0);
5964
}
6065

6166
[TestMethod]

0 commit comments

Comments
 (0)