Skip to content

Commit

Permalink
used $addFields operator instead of $set for backwards compability
Browse files Browse the repository at this point in the history
  • Loading branch information
gottscj committed Feb 7, 2024
1 parent 5698137 commit bea160e
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 42 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

## Change log

### v1.10.1
- Use $addFields operator instead of $set when setting DistributedLock heartbeat for support mongo versions < 4.2

### v1.10.0
- Update to Hangfire 1.8.9
- Use SlidingInvisibilityTimeout to determine whether a background job is still alive
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Description />
<Version>1.10.0</Version>
<Version>1.10.1</Version>
<Description>MongoDB storage implementation for Hangfire (background job system for ASP.NET applications).</Description>
<Copyright>Copyright © 2014-2019 Sergey Zwezdin, Martin Lobger, Jonas Gottschau</Copyright>
<Authors>Sergey Zwezdin, Martin Lobger, Jonas Gottschau</Authors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Description />
<Version>1.10.0</Version>
<Version>1.10.1</Version>
<Description>MongoDB storage implementation for Hangfire (background job system for ASP.NET applications).</Description>
<Copyright>Copyright © 2014-2019 Sergey Zwezdin, Martin Lobger, Jonas Gottschau</Copyright>
<Authors>Sergey Zwezdin, Martin Lobger, Jonas Gottschau</Authors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AssemblyName>Hangfire.Mongo.Sample.NETCore</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Hangfire.Mongo.Sample.NETCore</PackageId>
<Version>1.10.0</Version>
<Version>1.10.1</Version>
<Description>MongoDB storage implementation for Hangfire (background job system for ASP.NET applications).</Description>
<Copyright>Copyright © 2014-2019 Sergey Zwezdin, Martin Lobger, Jonas Gottschau</Copyright>
<Authors>Sergey Zwezdin, Martin Lobger, Jonas Gottschau</Authors>
Expand Down
71 changes: 39 additions & 32 deletions src/Hangfire.Mongo/DistributedLock/MongoDistributedLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class MongoDistributedLock : IDisposable
private static readonly ILog Logger = LogProvider.For<MongoDistributedLock>();

private static readonly ThreadLocal<Dictionary<string, int>> AcquiredLocks
= new ThreadLocal<Dictionary<string, int>>(() => new Dictionary<string, int>());
= new ThreadLocal<Dictionary<string, int>>(() => new Dictionary<string, int>());


private readonly string _resource;
Expand All @@ -43,8 +43,8 @@ public class MongoDistributedLock : IDisposable
/// <param name="storageOptions">Database options</param>
/// <exception cref="DistributedLockTimeoutException">Thrown if lock is not acquired within the timeout</exception>
/// <exception cref="MongoDistributedLockException">Thrown if other mongo specific issue prevented the lock to be acquired</exception>
public MongoDistributedLock(string resource,
TimeSpan timeout,
public MongoDistributedLock(string resource,
TimeSpan timeout,
HangfireDbContext dbContext,
MongoStorageOptions storageOptions)
{
Expand All @@ -57,9 +57,12 @@ public class MongoDistributedLock : IDisposable
{
throw new ArgumentException($@"The {nameof(resource)} cannot be empty", nameof(resource));
}

if (timeout.TotalSeconds > int.MaxValue)
{
throw new ArgumentException($"The timeout specified is too large. Please supply a timeout equal to or less than {int.MaxValue} seconds", nameof(timeout));
throw new ArgumentException(
$"The timeout specified is too large. Please supply a timeout equal to or less than {int.MaxValue} seconds",
nameof(timeout));
}
}

Expand Down Expand Up @@ -94,6 +97,7 @@ public virtual void Dispose()
{
return;
}

_completed = true;

if (!AcquiredLocks.Value.ContainsKey(_resource))
Expand Down Expand Up @@ -156,20 +160,22 @@ protected virtual void Acquire(TimeSpan timeout)
{
["$setOnInsert"] = new BsonDocument
{
[nameof(DistributedLockDto.ExpireAt)] = DateTime.UtcNow.Add(_storageOptions.DistributedLockLifetime)
[nameof(DistributedLockDto.ExpireAt)] =
DateTime.UtcNow.Add(_storageOptions.DistributedLockLifetime)
}
};
try
{
var result = _dbContext.DistributedLock.FindOneAndUpdate(filter, update, options);

// If result is null, it means we acquired the lock
if (result == null)
{
if (Logger.IsTraceEnabled())
{
Logger.Trace($"{_resource} - Acquired");
Logger.Trace($"{_resource} - Acquired");
}

isLockAcquired = true;
}
else
Expand All @@ -189,7 +195,8 @@ protected virtual void Acquire(TimeSpan timeout)

if (!isLockAcquired)
{
throw new DistributedLockTimeoutException($"{_resource} - Could not place a lock: The lock request timed out.");
throw new DistributedLockTimeoutException(
$"{_resource} - Could not place a lock: The lock request timed out.");
}
}
catch (DistributedLockTimeoutException)
Expand Down Expand Up @@ -222,8 +229,9 @@ protected virtual void Release()
{
if (Logger.IsTraceEnabled())
{
Logger.Trace($"{_resource} - Release");
Logger.Trace($"{_resource} - Release");
}

// Remove resource lock
_dbContext.DistributedLock.DeleteOne(new BsonDocument(nameof(DistributedLockDto.Resource), _resource));
}
Expand Down Expand Up @@ -262,37 +270,35 @@ protected virtual void Cleanup()
/// </summary>
protected virtual void StartHeartBeat()
{
var timerInterval = TimeSpan.FromMilliseconds(_storageOptions.DistributedLockLifetime.TotalMilliseconds / 5);
var timerInterval =
TimeSpan.FromMilliseconds(_storageOptions.DistributedLockLifetime.TotalMilliseconds / 5);
_heartbeatTimer = new Timer(_ =>
{
// Timer callback may be invoked after the Dispose method call,
// so we are using lock to avoid un synchronized calls.
lock (_lockObject)
{
if (_completed) return;
try
{
var filter = new BsonDocument
{
[nameof(DistributedLockDto.Resource)] = _resource
};
var update = new BsonDocument
var pipeline = new BsonDocument[]
{
[nameof(DistributedLockDto.ExpireAt)] = new BsonDocument
new BsonDocument("$match", new BsonDocument
{
["$add"] = new BsonArray
[nameof(DistributedLockDto.Resource)] = _resource
}),
new BsonDocument("$addFields", new BsonDocument
{
[nameof(DistributedLockDto.ExpireAt)] = new BsonDocument
{
"$$NOW",
(int) _storageOptions.DistributedLockLifetime.TotalMilliseconds,
["$add"] = new BsonArray
{
"$$NOW",
(int) _storageOptions.DistributedLockLifetime.TotalMilliseconds,
}
}
}
};
var pipeline = new BsonDocument[]
{
new BsonDocument("$match", filter),
new BsonDocument("$set", update)
})
};
Stopwatch sw = null;
if (Logger.IsTraceEnabled())
Expand All @@ -306,8 +312,8 @@ protected virtual void StartHeartBeat()
{
var serializedModel = new Dictionary<string, BsonDocument>
{
["Filter"] = filter,
["Update"] = update
["Filter"] = pipeline[0],
["Update"] = pipeline[1]
};
sw.Stop();
var builder = new StringBuilder();
Expand All @@ -324,7 +330,7 @@ protected virtual void StartHeartBeat()
}
}, null, timerInterval, timerInterval);
}

/// <summary>
///
/// </summary>
Expand All @@ -335,13 +341,14 @@ protected virtual DateTime Wait(string resource, TimeSpan timeout)
{
if (Logger.IsTraceEnabled())
{
Logger.Trace($"{resource} - Waiting {timeout.TotalMilliseconds}ms");
Logger.Trace($"{resource} - Waiting {timeout.TotalMilliseconds}ms");
}

using (var resetEvent = new ManualResetEvent(false))
{
resetEvent.WaitOne(timeout);
}

return DateTime.UtcNow;
}
}
Expand Down
10 changes: 3 additions & 7 deletions src/Hangfire.Mongo/Hangfire.Mongo.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>1.10.0</VersionPrefix>
<VersionPrefix>1.10.1</VersionPrefix>
<TargetFramework>netstandard2.0</TargetFramework>
<NoWarn>$(NoWarn);CS0618</NoWarn>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand All @@ -21,12 +21,8 @@
<owners>Sergey Zwezdin, Jonas Gottschau</owners>
<Description>MongoDB storage implementation for Hangfire (background job system for ASP.NET applications).</Description>
<PackageTags>Hangfire AspNet OWIN MongoDB CosmosDB Long-Running Background Fire-And-Forget Delayed Recurring Tasks Jobs Scheduler Threading Queues</PackageTags>
<PackageReleaseNotes>1.10.0
- Update to Hangfire 1.8.9
- Use SlidingInvisibilityTimeout to determine whether a background job is still alive
- BREAKING: Remove InvisibilityTimeout
- Use server time for distributed lock instead of Datetime.UtcNow
- Fixed Job not requeued when requeued while in processing state (#380)
<PackageReleaseNotes>1.10.1
- Use $addFields operator instead of $set when setting DistributedLock heartbeat for support mongo versions &lt; 4.2
</PackageReleaseNotes>
<PackageReadmeFile>README.md</PackageReadmeFile>
<!--<PackageLicenseUrl>https://raw.githubusercontent.com/sergun/Hangfire.Mongo/master/LICENSE</PackageLicenseUrl>-->
Expand Down

0 comments on commit bea160e

Please sign in to comment.