-
-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* fix cosmosdb requires all unique indexes to have fields #362 * update version * add job queue watch add retry for bulkwrites * minor optimization
- Loading branch information
Showing
14 changed files
with
396 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System; | ||
using Hangfire.Mongo.Database; | ||
|
||
namespace Hangfire.Mongo.CosmosDB; | ||
|
||
/// <inheritdoc /> | ||
public class CosmosConnection : MongoConnection | ||
{ | ||
/// <inheritdoc /> | ||
public CosmosConnection(HangfireDbContext database, MongoStorageOptions storageOptions) | ||
: base(database, storageOptions) | ||
{ | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override DateTime GetUtcDateTime() | ||
{ | ||
return DateTime.UtcNow; | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
src/Hangfire.Mongo/CosmosDB/CosmosDbWriteOnlyTransaction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Hangfire.Common; | ||
using Hangfire.Logging; | ||
using Hangfire.Mongo.Database; | ||
using Hangfire.Mongo.Dto; | ||
using Hangfire.Storage; | ||
using MongoDB.Bson; | ||
using MongoDB.Driver; | ||
|
||
namespace Hangfire.Mongo.CosmosDB; | ||
|
||
#pragma warning disable 1591 | ||
|
||
public class CosmosDbWriteOnlyTransaction : MongoWriteOnlyTransaction | ||
{ | ||
public CosmosDbWriteOnlyTransaction(HangfireDbContext dbContext, MongoStorageOptions storageOptions) : base( | ||
dbContext, storageOptions) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// check if we are inserting a Job, add the "Key" field as this is required in cosmos as there is | ||
/// unique index for this field | ||
/// </summary> | ||
/// <param name="jobGraph"></param> | ||
/// <param name="writeModels"></param> | ||
/// <param name="bulkWriteOptions"></param> | ||
protected override void ExecuteCommit(IMongoCollection<BsonDocument> jobGraph, List<WriteModel<BsonDocument>> writeModels, BulkWriteOptions bulkWriteOptions) | ||
{ | ||
foreach (var insertOneModel in writeModels.OfType<InsertOneModel<BsonDocument>>()) | ||
{ | ||
var typeArray = insertOneModel.Document["_t"].AsBsonArray; | ||
if (typeArray.Contains("JobDto")) | ||
{ | ||
insertOneModel.Document[nameof(KeyJobDto.Key)] = insertOneModel.Document["_id"].ToString(); | ||
} | ||
} | ||
|
||
var trys = 3; | ||
do | ||
{ | ||
try | ||
{ | ||
base.ExecuteCommit(jobGraph, writeModels, bulkWriteOptions); | ||
break; | ||
} | ||
catch (Exception e) | ||
{ | ||
trys -= 1; | ||
Logger.WarnException("Error writing to DB", e); | ||
if (trys == 0) | ||
{ | ||
Logger.ErrorException("Throwing after 3 re-trys", e); | ||
throw; | ||
} | ||
} | ||
} while (true); | ||
} | ||
} | ||
|
||
#pragma warning restore 1591 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Hangfire.Mongo.Database; | ||
|
||
namespace Hangfire.Mongo.CosmosDB; | ||
|
||
/// <inheritdoc /> | ||
public class CosmosFactory : MongoFactory | ||
{ | ||
/// <inheritdoc /> | ||
public override MongoWriteOnlyTransaction CreateMongoWriteOnlyTransaction(HangfireDbContext dbContext, | ||
MongoStorageOptions storageOptions) | ||
{ | ||
return new CosmosDbWriteOnlyTransaction(dbContext, storageOptions); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override MongoConnection CreateMongoConnection(HangfireDbContext dbContext, MongoStorageOptions storageOptions) | ||
{ | ||
return new CosmosConnection(dbContext, storageOptions); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override MongoJobQueueWatcher CreateMongoJobQueueWatcher(HangfireDbContext dbContext, MongoStorageOptions storageOptions) | ||
{ | ||
return new CosmosQueueWatcher(dbContext, storageOptions, JobQueueSemaphore); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
using System; | ||
using System.Threading; | ||
using Hangfire.Logging; | ||
using Hangfire.Mongo.Database; | ||
using Hangfire.Mongo.Dto; | ||
using Hangfire.States; | ||
using MongoDB.Bson; | ||
using MongoDB.Driver; | ||
|
||
namespace Hangfire.Mongo.CosmosDB; | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
public class CosmosQueueWatcher : MongoJobQueueWatcher | ||
{ | ||
|
||
/// <summary> | ||
/// ctor | ||
/// </summary> | ||
/// <param name="dbContext"></param> | ||
/// <param name="storageOptions"></param> | ||
/// <param name="jobQueueSemaphore"></param> | ||
public CosmosQueueWatcher(HangfireDbContext dbContext, | ||
MongoStorageOptions storageOptions, | ||
IJobQueueSemaphore jobQueueSemaphore) | ||
: base(dbContext, storageOptions, jobQueueSemaphore) | ||
{ | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override void Execute(CancellationToken cancellationToken) | ||
{ | ||
Logger.Warn("Be careful using Watch. Its not thoroughly tested!"); | ||
var pipeline = new[] | ||
{ | ||
new BsonDocument | ||
{ | ||
["$match"] = new BsonDocument | ||
{ | ||
["operationType"] = new BsonDocument | ||
{ | ||
["$in"] = new BsonArray | ||
{ | ||
"insert", "update", "replace" | ||
} | ||
} | ||
} | ||
}, | ||
new BsonDocument | ||
{ | ||
["$project"] = new BsonDocument | ||
{ | ||
["_id"] = 1, | ||
["fullDocument"] = 1, | ||
["ns"] = 1, | ||
["documentKey"] = 1 | ||
} | ||
} | ||
}; | ||
|
||
while (!cancellationToken.IsCancellationRequested) | ||
{ | ||
try | ||
{ | ||
var cursor = DbContext | ||
.Database | ||
.GetCollection<BsonDocument>(DbContext.JobGraph.CollectionNamespace.CollectionName) | ||
.Watch<BsonDocument>(pipeline, new ChangeStreamOptions | ||
{ | ||
FullDocument = ChangeStreamFullDocumentOption.UpdateLookup | ||
}); | ||
|
||
if (Logger.IsTraceEnabled()) | ||
{ | ||
Logger.Trace("Watcher: Watching for enqueued jobs"); | ||
} | ||
|
||
foreach (var change in cursor.ToEnumerable(cancellationToken)) | ||
{ | ||
var doc = change["fullDocument"].AsBsonDocument; | ||
var types = doc["_t"].AsBsonArray; | ||
|
||
if (!types.Contains("JobDto")) | ||
{ | ||
continue; | ||
} | ||
|
||
var stateName = doc[nameof(JobDto.StateName)]; | ||
if (stateName == BsonNull.Value || | ||
stateName != EnqueuedState.StateName) | ||
{ | ||
continue; | ||
} | ||
|
||
// var queue = change["updateDescription"]["updatedFields"][nameof(JobDto.Queue)].AsString; | ||
JobQueueSemaphore.Release(doc[nameof(JobDto.Queue)].AsString); | ||
if (Logger.IsTraceEnabled()) | ||
{ | ||
Logger.Trace("Watcher: Job enqueued, queue: " + doc[nameof(JobDto.Queue)].AsString); | ||
} | ||
} | ||
} | ||
catch (MongoCommandException e) | ||
{ | ||
if (e.Message.Contains("$changeStream stage is only supported on replica sets")) | ||
{ | ||
Logger.ErrorException( | ||
"Current db does not support change stream (not a replica set, https://docs.mongodb.com/manual/reference/method/db.collection.watch/)\r\n" + | ||
"if you need instant (almost) handling of enqueued jobs, please set 'CheckQueuedJobsStrategy' to 'TailNotificationsCollection' in MongoStorageOptions", | ||
e); | ||
throw; | ||
} | ||
|
||
// wait max allowed | ||
cancellationToken.WaitHandle.WaitOne(MongoNotificationObserver.MaxTimeout); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.