@@ -1,8 +1,5 @@ | |||||
using System; | using System; | ||||
using System.Threading.Tasks; | |||||
using DotNetCore.CAP; | using DotNetCore.CAP; | ||||
using DotNetCore.CAP.Abstractions; | |||||
using DotNetCore.CAP.MongoDB; | |||||
using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||
using MongoDB.Bson; | using MongoDB.Bson; | ||||
using MongoDB.Driver; | using MongoDB.Driver; | ||||
@@ -15,71 +12,48 @@ namespace Sample.RabbitMQ.MongoDB.Controllers | |||||
{ | { | ||||
private readonly IMongoClient _client; | private readonly IMongoClient _client; | ||||
private readonly ICapPublisher _capPublisher; | private readonly ICapPublisher _capPublisher; | ||||
private readonly IMongoTransaction _mongoTransaction; | |||||
public ValuesController(IMongoClient client, ICapPublisher capPublisher, IMongoTransaction mongoTransaction) | |||||
public ValuesController(IMongoClient client, ICapPublisher capPublisher) | |||||
{ | { | ||||
_client = client; | _client = client; | ||||
_capPublisher = capPublisher; | _capPublisher = capPublisher; | ||||
_mongoTransaction = mongoTransaction; | |||||
} | } | ||||
[Route("~/publish")] | [Route("~/publish")] | ||||
public async Task<IActionResult> PublishWithTrans() | |||||
public IActionResult PublishWithTrans() | |||||
{ | { | ||||
using (var trans = await _mongoTransaction.BegeinAsync()) | |||||
using (var session = _client.StartSession()) | |||||
using (var trans = _capPublisher.CapTransaction.Begin(session)) | |||||
{ | { | ||||
var collection = _client.GetDatabase("TEST").GetCollection<BsonDocument>("test"); | var collection = _client.GetDatabase("TEST").GetCollection<BsonDocument>("test"); | ||||
collection.InsertOne(trans.GetSession(), new BsonDocument { { "hello", "world" } }); | |||||
collection.InsertOne(session, new BsonDocument { { "hello", "world" } }); | |||||
await _capPublisher.PublishWithMongoAsync("sample.rabbitmq.mongodb", DateTime.Now, trans); | |||||
_capPublisher.Publish("sample.rabbitmq.mongodb", DateTime.Now); | |||||
trans.Commit(); | |||||
} | } | ||||
return Ok(); | return Ok(); | ||||
} | } | ||||
[Route("~/publish/not/autocommit")] | |||||
[Route("~/publish/autocommit")] | |||||
public IActionResult PublishNotAutoCommit() | public IActionResult PublishNotAutoCommit() | ||||
{ | { | ||||
using (var trans = _mongoTransaction.Begein(autoCommit: false)) | |||||
using (var session = _client.StartSession()) | |||||
using (_capPublisher.CapTransaction.Begin(session,true)) | |||||
{ | { | ||||
var session = trans.GetSession(); | |||||
var collection = _client.GetDatabase("TEST").GetCollection<BsonDocument>("test"); | var collection = _client.GetDatabase("TEST").GetCollection<BsonDocument>("test"); | ||||
collection.InsertOne(session, new BsonDocument { { "Hello", "World" } }); | |||||
_capPublisher.PublishWithMongo("sample.rabbitmq.mongodb", DateTime.Now, trans); | |||||
collection.InsertOne(session, new BsonDocument { { "hello", "world" } }); | |||||
//Do something, and commit by yourself. | |||||
session.CommitTransaction(); | |||||
_capPublisher.Publish("sample.rabbitmq.mongodb", DateTime.Now); | |||||
} | } | ||||
return Ok(); | |||||
} | |||||
[Route("~/publish/rollback")] | |||||
public IActionResult PublishRollback() | |||||
{ | |||||
using (var trans = _mongoTransaction.Begein(autoCommit: false)) | |||||
{ | |||||
var session = trans.GetSession(); | |||||
try | |||||
{ | |||||
_capPublisher.PublishWithMongo("sample.rabbitmq.mongodb", DateTime.Now, trans); | |||||
//Do something, but | |||||
throw new Exception("Foo"); | |||||
session.CommitTransaction(); | |||||
} | |||||
catch (System.Exception ex) | |||||
{ | |||||
session.AbortTransaction(); | |||||
return StatusCode(500, ex.Message); | |||||
} | |||||
} | |||||
return Ok(); | |||||
} | } | ||||
[Route("~/publish/without/trans")] | [Route("~/publish/without/trans")] | ||||
public IActionResult PublishWithoutTrans() | public IActionResult PublishWithoutTrans() | ||||
{ | { | ||||
_capPublisher.PublishWithMongo("sample.rabbitmq.mongodb", DateTime.Now); | |||||
_capPublisher.Publish("sample.rabbitmq.mongodb", DateTime.Now); | |||||
return Ok(); | return Ok(); | ||||
} | } | ||||
@@ -2,7 +2,6 @@ | |||||
// Licensed under the MIT License. See License.txt in the project root for license information. | // Licensed under the MIT License. See License.txt in the project root for license information. | ||||
using System; | using System; | ||||
using DotNetCore.CAP.Abstractions; | |||||
using DotNetCore.CAP.Processor; | using DotNetCore.CAP.Processor; | ||||
using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||
@@ -28,7 +27,6 @@ namespace DotNetCore.CAP.MongoDB | |||||
services.AddScoped<ICallbackPublisher, CapPublisher>(); | services.AddScoped<ICallbackPublisher, CapPublisher>(); | ||||
services.AddTransient<ICollectProcessor, MongoDBCollectProcessor>(); | services.AddTransient<ICollectProcessor, MongoDBCollectProcessor>(); | ||||
services.AddTransient<IMongoTransaction, MongoTransaction>(); | |||||
var options = new MongoDBOptions(); | var options = new MongoDBOptions(); | ||||
_configure?.Invoke(options); | _configure?.Invoke(options); | ||||
@@ -29,7 +29,5 @@ namespace DotNetCore.CAP.MongoDB | |||||
/// Default value: "published" | /// Default value: "published" | ||||
/// </summary> | /// </summary> | ||||
public string PublishedCollection { get; set; } = "cap.published"; | public string PublishedCollection { get; set; } = "cap.published"; | ||||
internal const string CounterCollection = "cap.counter"; | |||||
} | } | ||||
} | } |
@@ -2,13 +2,11 @@ | |||||
// Licensed under the MIT License. See License.txt in the project root for license information. | // Licensed under the MIT License. See License.txt in the project root for license information. | ||||
using System; | using System; | ||||
using System.Data; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using DotNetCore.CAP.Abstractions; | using DotNetCore.CAP.Abstractions; | ||||
using DotNetCore.CAP.Diagnostics; | |||||
using DotNetCore.CAP.Infrastructure; | |||||
using DotNetCore.CAP.Models; | using DotNetCore.CAP.Models; | ||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using MongoDB.Driver; | using MongoDB.Driver; | ||||
namespace DotNetCore.CAP.MongoDB | namespace DotNetCore.CAP.MongoDB | ||||
@@ -16,187 +14,37 @@ namespace DotNetCore.CAP.MongoDB | |||||
public class CapPublisher : CapPublisherBase, ICallbackPublisher | public class CapPublisher : CapPublisherBase, ICallbackPublisher | ||||
{ | { | ||||
private readonly MongoDBOptions _options; | private readonly MongoDBOptions _options; | ||||
private readonly IMongoDatabase _database; | |||||
private bool _usingTransaction = true; | |||||
public CapPublisher( | |||||
ILogger<CapPublisherBase> logger, | |||||
IDispatcher dispatcher, | |||||
IMongoClient client, | |||||
MongoDBOptions options, | |||||
IServiceProvider provider) | |||||
: base(logger, dispatcher) | |||||
public CapPublisher(IServiceProvider provider, MongoDBOptions options) | |||||
: base(provider) | |||||
{ | { | ||||
_options = options; | _options = options; | ||||
_database = client.GetDatabase(_options.DatabaseName); | |||||
ServiceProvider = provider; | |||||
} | } | ||||
public async Task PublishCallbackAsync(CapPublishedMessage message) | public async Task PublishCallbackAsync(CapPublishedMessage message) | ||||
{ | { | ||||
var collection = _database.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | |||||
message.Id = await new MongoDBUtil().GetNextSequenceValueAsync(_database, _options.PublishedCollection); | |||||
collection.InsertOne(message); | |||||
Enqueue(message); | |||||
await PublishAsyncInternal(message); | |||||
} | } | ||||
protected override int Execute(IDbConnection dbConnection, IDbTransaction dbTransaction, | |||||
CapPublishedMessage message) | |||||
protected override Task ExecuteAsync(CapPublishedMessage message, ICapTransaction transaction, | |||||
CancellationToken cancel = default(CancellationToken)) | |||||
{ | { | ||||
throw new NotImplementedException("Not work for MongoDB"); | |||||
} | |||||
protected override Task<int> ExecuteAsync(IDbConnection dbConnection, IDbTransaction dbTransaction, | |||||
CapPublishedMessage message) | |||||
{ | |||||
throw new NotImplementedException("Not work for MongoDB"); | |||||
} | |||||
protected override void PrepareConnectionForEF() | |||||
{ | |||||
throw new NotImplementedException("Not work for MongoDB"); | |||||
} | |||||
public override void PublishWithMongo<T>(string name, T contentObj, IMongoTransaction mongoTransaction = null, string callbackName = null) | |||||
{ | |||||
if (mongoTransaction == null) | |||||
{ | |||||
_usingTransaction = false; | |||||
mongoTransaction = new NullMongoTransaction(); | |||||
} | |||||
PublishWithTransaction<T>(name, contentObj, mongoTransaction, callbackName); | |||||
} | |||||
var dbTrans = (IClientSessionHandle)transaction.DbTransaction; | |||||
public override async Task PublishWithMongoAsync<T>(string name, T contentObj, IMongoTransaction mongoTransaction = null, string callbackName = null) | |||||
{ | |||||
if (mongoTransaction == null) | |||||
{ | |||||
_usingTransaction = false; | |||||
mongoTransaction = new NullMongoTransaction(); | |||||
} | |||||
var collection = dbTrans.Client | |||||
.GetDatabase(_options.DatabaseName) | |||||
.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | |||||
await PublishWithTransactionAsync<T>(name, contentObj, mongoTransaction, callbackName); | |||||
var insertOptions = new InsertOneOptions { BypassDocumentValidation = false }; | |||||
return collection.InsertOneAsync(dbTrans, message, insertOptions, cancel); | |||||
} | } | ||||
private void PublishWithTransaction<T>(string name, T contentObj, IMongoTransaction transaction, string callbackName) | |||||
protected override object GetDbTransaction() | |||||
{ | { | ||||
var operationId = default(Guid); | |||||
var content = Serialize(contentObj, callbackName); | |||||
var message = new CapPublishedMessage | |||||
{ | |||||
Name = name, | |||||
Content = content, | |||||
StatusName = StatusName.Scheduled | |||||
}; | |||||
var session = transaction.GetSession(); | |||||
try | |||||
{ | |||||
operationId = s_diagnosticListener.WritePublishMessageStoreBefore(message); | |||||
var id = Execute(session, message); | |||||
if (transaction.AutoCommit) | |||||
{ | |||||
session.CommitTransaction(); | |||||
} | |||||
if (!_usingTransaction || (transaction.AutoCommit && id > 0)) | |||||
{ | |||||
_logger.LogInformation($"message [{message}] has been persisted in the database."); | |||||
s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); | |||||
message.Id = id; | |||||
Enqueue(message); | |||||
} | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
_logger.LogError(e, "An exception was occurred when publish message. message:" + name); | |||||
s_diagnosticListener.WritePublishMessageStoreError(operationId, message, e); | |||||
throw; | |||||
} | |||||
} | |||||
private int Execute(IClientSessionHandle session, CapPublishedMessage message) | |||||
{ | |||||
message.Id = new MongoDBUtil().GetNextSequenceValue(_database, _options.PublishedCollection, session); | |||||
var collection = _database.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | |||||
if (_usingTransaction) | |||||
{ | |||||
collection.InsertOne(session, message); | |||||
} | |||||
else | |||||
{ | |||||
collection.InsertOne(message); | |||||
} | |||||
return message.Id; | |||||
} | |||||
private async Task PublishWithTransactionAsync<T>(string name, T contentObj, IMongoTransaction transaction, string callbackName) | |||||
{ | |||||
var operationId = default(Guid); | |||||
var content = Serialize(contentObj, callbackName); | |||||
var message = new CapPublishedMessage | |||||
{ | |||||
Name = name, | |||||
Content = content, | |||||
StatusName = StatusName.Scheduled | |||||
}; | |||||
var session = transaction.GetSession(); | |||||
try | |||||
{ | |||||
operationId = s_diagnosticListener.WritePublishMessageStoreBefore(message); | |||||
var id = await ExecuteAsync(session, message); | |||||
if (transaction.AutoCommit) | |||||
{ | |||||
await session.CommitTransactionAsync(); | |||||
} | |||||
if (!_usingTransaction || (transaction.AutoCommit && id > 0)) | |||||
{ | |||||
_logger.LogInformation($"message [{message}] has been persisted in the database."); | |||||
s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); | |||||
message.Id = id; | |||||
Enqueue(message); | |||||
} | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
_logger.LogError(e, "An exception was occurred when publish message async. exception message:" + name); | |||||
s_diagnosticListener.WritePublishMessageStoreError(operationId, message, e); | |||||
Console.WriteLine(e); | |||||
throw; | |||||
} | |||||
} | |||||
private async Task<int> ExecuteAsync(IClientSessionHandle session, CapPublishedMessage message) | |||||
{ | |||||
message.Id = | |||||
await new MongoDBUtil().GetNextSequenceValueAsync(_database, _options.PublishedCollection, session); | |||||
var collection = _database.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | |||||
if (_usingTransaction) | |||||
{ | |||||
await collection.InsertOneAsync(session, message); | |||||
} | |||||
else | |||||
{ | |||||
await collection.InsertOneAsync(message); | |||||
} | |||||
return message.Id; | |||||
var client = ServiceProvider.GetRequiredService<IMongoClient>(); | |||||
var session = client.StartSession(new ClientSessionOptions()); | |||||
session.StartTransaction(); | |||||
return session; | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,54 @@ | |||||
using System.Data; | |||||
using System.Diagnostics; | |||||
using MongoDB.Driver; | |||||
// ReSharper disable once CheckNamespace | |||||
namespace DotNetCore.CAP | |||||
{ | |||||
public class MongoDBCapTransaction : CapTransactionBase | |||||
{ | |||||
public MongoDBCapTransaction(IDispatcher dispatcher) | |||||
: base(dispatcher) | |||||
{ | |||||
} | |||||
public override void Commit() | |||||
{ | |||||
Debug.Assert(DbTransaction != null); | |||||
if (DbTransaction is IClientSessionHandle session) | |||||
{ | |||||
session.CommitTransaction(); | |||||
} | |||||
Flush(); | |||||
} | |||||
public override void Rollback() | |||||
{ | |||||
Debug.Assert(DbTransaction != null); | |||||
if (DbTransaction is IClientSessionHandle session) | |||||
{ | |||||
session.AbortTransaction(); | |||||
} | |||||
} | |||||
public override void Dispose() | |||||
{ | |||||
(DbTransaction as IDbTransaction)?.Dispose(); | |||||
} | |||||
} | |||||
public static class CapTransactionExtensions | |||||
{ | |||||
public static ICapTransaction Begin(this ICapTransaction transaction, | |||||
IClientSessionHandle dbTransaction, bool autoCommit = false) | |||||
{ | |||||
transaction.DbTransaction = dbTransaction; | |||||
transaction.AutoCommit = autoCommit; | |||||
return transaction; | |||||
} | |||||
} | |||||
} |
@@ -6,7 +6,6 @@ using System.Threading; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using DotNetCore.CAP.Dashboard; | using DotNetCore.CAP.Dashboard; | ||||
using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
using MongoDB.Bson; | |||||
using MongoDB.Driver; | using MongoDB.Driver; | ||||
namespace DotNetCore.CAP.MongoDB | namespace DotNetCore.CAP.MongoDB | ||||
@@ -49,26 +48,14 @@ namespace DotNetCore.CAP.MongoDB | |||||
var database = _client.GetDatabase(_options.DatabaseName); | var database = _client.GetDatabase(_options.DatabaseName); | ||||
var names = (await database.ListCollectionNamesAsync(cancellationToken: cancellationToken))?.ToList(); | var names = (await database.ListCollectionNamesAsync(cancellationToken: cancellationToken))?.ToList(); | ||||
if (!names.Any(n => n == _options.ReceivedCollection)) | |||||
if (names.All(n => n != _options.ReceivedCollection)) | |||||
{ | { | ||||
await database.CreateCollectionAsync(_options.ReceivedCollection, cancellationToken: cancellationToken); | await database.CreateCollectionAsync(_options.ReceivedCollection, cancellationToken: cancellationToken); | ||||
} | } | ||||
if (names.All(n => n != _options.PublishedCollection)) | if (names.All(n => n != _options.PublishedCollection)) | ||||
{ | { | ||||
await database.CreateCollectionAsync(_options.PublishedCollection, | |||||
cancellationToken: cancellationToken); | |||||
} | |||||
if (names.All(n => n != MongoDBOptions.CounterCollection)) | |||||
{ | |||||
await database.CreateCollectionAsync(MongoDBOptions.CounterCollection, cancellationToken: cancellationToken); | |||||
var collection = database.GetCollection<BsonDocument>(MongoDBOptions.CounterCollection); | |||||
await collection.InsertManyAsync(new[] | |||||
{ | |||||
new BsonDocument {{"_id", _options.PublishedCollection}, {"sequence_value", 0}}, | |||||
new BsonDocument {{"_id", _options.ReceivedCollection}, {"sequence_value", 0}} | |||||
}, cancellationToken: cancellationToken); | |||||
await database.CreateCollectionAsync(_options.PublishedCollection, cancellationToken: cancellationToken); | |||||
} | } | ||||
_logger.LogDebug("Ensuring all create database tables script are applied."); | _logger.LogDebug("Ensuring all create database tables script are applied."); | ||||
@@ -25,7 +25,7 @@ namespace DotNetCore.CAP.MongoDB | |||||
_database = _client.GetDatabase(_options.DatabaseName); | _database = _client.GetDatabase(_options.DatabaseName); | ||||
} | } | ||||
public bool ChangePublishedState(int messageId, string state) | |||||
public bool ChangePublishedState(long messageId, string state) | |||||
{ | { | ||||
var collection = _database.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | var collection = _database.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | ||||
@@ -40,7 +40,7 @@ namespace DotNetCore.CAP.MongoDB | |||||
return result.ModifiedCount > 0; | return result.ModifiedCount > 0; | ||||
} | } | ||||
public bool ChangeReceivedState(int messageId, string state) | |||||
public bool ChangeReceivedState(long messageId, string state) | |||||
{ | { | ||||
var collection = _database.GetCollection<CapReceivedMessage>(_options.ReceivedCollection); | var collection = _database.GetCollection<CapReceivedMessage>(_options.ReceivedCollection); | ||||
@@ -60,7 +60,7 @@ namespace DotNetCore.CAP.MongoDB | |||||
return new MongoDBStorageTransaction(_client, _options); | return new MongoDBStorageTransaction(_client, _options); | ||||
} | } | ||||
public async Task<CapPublishedMessage> GetPublishedMessageAsync(int id) | |||||
public async Task<CapPublishedMessage> GetPublishedMessageAsync(long id) | |||||
{ | { | ||||
var collection = _database.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | var collection = _database.GetCollection<CapPublishedMessage>(_options.PublishedCollection); | ||||
return await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); | return await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); | ||||
@@ -77,7 +77,7 @@ namespace DotNetCore.CAP.MongoDB | |||||
.ToListAsync(); | .ToListAsync(); | ||||
} | } | ||||
public async Task<CapReceivedMessage> GetReceivedMessageAsync(int id) | |||||
public async Task<CapReceivedMessage> GetReceivedMessageAsync(long id) | |||||
{ | { | ||||
var collection = _database.GetCollection<CapReceivedMessage>(_options.ReceivedCollection); | var collection = _database.GetCollection<CapReceivedMessage>(_options.ReceivedCollection); | ||||
return await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); | return await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); | ||||
@@ -95,7 +95,7 @@ namespace DotNetCore.CAP.MongoDB | |||||
.ToListAsync(); | .ToListAsync(); | ||||
} | } | ||||
public async Task<int> StoreReceivedMessageAsync(CapReceivedMessage message) | |||||
public void StoreReceivedMessage(CapReceivedMessage message) | |||||
{ | { | ||||
if (message == null) | if (message == null) | ||||
{ | { | ||||
@@ -104,11 +104,7 @@ namespace DotNetCore.CAP.MongoDB | |||||
var collection = _database.GetCollection<CapReceivedMessage>(_options.ReceivedCollection); | var collection = _database.GetCollection<CapReceivedMessage>(_options.ReceivedCollection); | ||||
message.Id = await new MongoDBUtil().GetNextSequenceValueAsync(_database, _options.ReceivedCollection); | |||||
collection.InsertOne(message); | collection.InsertOne(message); | ||||
return message.Id; | |||||
} | } | ||||
public void Dispose() | public void Dispose() | ||||
@@ -1,66 +0,0 @@ | |||||
// Copyright (c) .NET Core Community. All rights reserved. | |||||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using MongoDB.Bson; | |||||
using MongoDB.Driver; | |||||
namespace DotNetCore.CAP.MongoDB | |||||
{ | |||||
internal class MongoDBUtil | |||||
{ | |||||
private readonly FindOneAndUpdateOptions<BsonDocument> _options = new FindOneAndUpdateOptions<BsonDocument> | |||||
{ | |||||
ReturnDocument = ReturnDocument.After | |||||
}; | |||||
public async Task<int> GetNextSequenceValueAsync(IMongoDatabase database, string collectionName, | |||||
IClientSessionHandle session = null) | |||||
{ | |||||
//https://www.tutorialspoint.com/mongodb/mongodb_autoincrement_sequence.htm | |||||
var collection = database.GetCollection<BsonDocument>(MongoDBOptions.CounterCollection); | |||||
var updateDef = Builders<BsonDocument>.Update.Inc("sequence_value", 1); | |||||
var filter = new BsonDocument { { "_id", collectionName } }; | |||||
BsonDocument result; | |||||
if (session == null) | |||||
{ | |||||
result = await collection.FindOneAndUpdateAsync(filter, updateDef, _options); | |||||
} | |||||
else | |||||
{ | |||||
result = await collection.FindOneAndUpdateAsync(session, filter, updateDef, _options); | |||||
} | |||||
if (result.TryGetValue("sequence_value", out var value)) | |||||
{ | |||||
return value.ToInt32(); | |||||
} | |||||
throw new Exception("Unable to get next sequence value."); | |||||
} | |||||
public int GetNextSequenceValue(IMongoDatabase database, string collectionName, | |||||
IClientSessionHandle session = null) | |||||
{ | |||||
var collection = database.GetCollection<BsonDocument>(MongoDBOptions.CounterCollection); | |||||
var filter = new BsonDocument { { "_id", collectionName } }; | |||||
var updateDef = Builders<BsonDocument>.Update.Inc("sequence_value", 1); | |||||
var result = session == null | |||||
? collection.FindOneAndUpdate(filter, updateDef, _options) | |||||
: collection.FindOneAndUpdate(session, filter, updateDef, _options); | |||||
if (result.TryGetValue("sequence_value", out var value)) | |||||
{ | |||||
return value.ToInt32(); | |||||
} | |||||
throw new Exception("Unable to get next sequence value."); | |||||
} | |||||
} | |||||
} |
@@ -1,60 +0,0 @@ | |||||
// Copyright (c) .NET Core Community. All rights reserved. | |||||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||||
using System.Threading.Tasks; | |||||
using DotNetCore.CAP.Abstractions; | |||||
using MongoDB.Driver; | |||||
namespace DotNetCore.CAP.MongoDB | |||||
{ | |||||
public class MongoTransaction : IMongoTransaction | |||||
{ | |||||
private readonly IMongoClient _client; | |||||
public MongoTransaction(IMongoClient client) | |||||
{ | |||||
_client = client; | |||||
} | |||||
public IClientSessionHandle Session { get; set; } | |||||
public bool AutoCommit { get; set; } | |||||
public async Task<IMongoTransaction> BegeinAsync(bool autoCommit = true) | |||||
{ | |||||
AutoCommit = autoCommit; | |||||
Session = await _client.StartSessionAsync(); | |||||
Session.StartTransaction(); | |||||
return this; | |||||
} | |||||
public IMongoTransaction Begein(bool autoCommit = true) | |||||
{ | |||||
AutoCommit = autoCommit; | |||||
Session = _client.StartSession(); | |||||
Session.StartTransaction(); | |||||
return this; | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
Session?.Dispose(); | |||||
} | |||||
} | |||||
public class NullMongoTransaction : MongoTransaction | |||||
{ | |||||
public NullMongoTransaction(IMongoClient client = null) : base(client) | |||||
{ | |||||
AutoCommit = false; | |||||
} | |||||
} | |||||
public static class MongoTransactionExtensions | |||||
{ | |||||
public static IClientSessionHandle GetSession(this IMongoTransaction mongoTransaction) | |||||
{ | |||||
var trans = mongoTransaction as MongoTransaction; | |||||
return trans?.Session; | |||||
} | |||||
} | |||||
} |
@@ -24,8 +24,10 @@ namespace DotNetCore.CAP | |||||
services.AddSingleton<CapDatabaseStorageMarkerService>(); | services.AddSingleton<CapDatabaseStorageMarkerService>(); | ||||
services.AddSingleton<IStorage, MySqlStorage>(); | services.AddSingleton<IStorage, MySqlStorage>(); | ||||
services.AddSingleton<IStorageConnection, MySqlStorageConnection>(); | services.AddSingleton<IStorageConnection, MySqlStorageConnection>(); | ||||
services.AddScoped<ICapPublisher, CapPublisher>(); | services.AddScoped<ICapPublisher, CapPublisher>(); | ||||
services.AddScoped<ICallbackPublisher, CapPublisher>(); | services.AddScoped<ICallbackPublisher, CapPublisher>(); | ||||
services.AddTransient<ICollectProcessor, MySqlCollectProcessor>(); | services.AddTransient<ICollectProcessor, MySqlCollectProcessor>(); | ||||
services.AddTransient<CapTransactionBase, MySqlCapTransaction>(); | services.AddTransient<CapTransactionBase, MySqlCapTransaction>(); | ||||
@@ -1,6 +1,7 @@ | |||||
// Copyright (c) .NET Core Community. All rights reserved. | // Copyright (c) .NET Core Community. All rights reserved. | ||||
// Licensed under the MIT License. See License.txt in the project root for license information. | // Licensed under the MIT License. See License.txt in the project root for license information. | ||||
// ReSharper disable once CheckNamespace | |||||
namespace DotNetCore.CAP | namespace DotNetCore.CAP | ||||
{ | { | ||||
public class MySqlOptions : EFOptions | public class MySqlOptions : EFOptions | ||||
@@ -1,21 +0,0 @@ | |||||
// Copyright (c) .NET Core Community. All rights reserved. | |||||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
namespace DotNetCore.CAP.Abstractions | |||||
{ | |||||
public interface IMongoTransaction : IDisposable | |||||
{ | |||||
/// <summary> | |||||
/// If set true, the session.CommitTransaction() will be called automatically. | |||||
/// </summary> | |||||
/// <value></value> | |||||
bool AutoCommit { get; set; } | |||||
Task<IMongoTransaction> BegeinAsync(bool autoCommit = true); | |||||
IMongoTransaction Begein(bool autoCommit = true); | |||||
} | |||||
} |