Commit 9b4f3d14 authored by Savorboard's avatar Savorboard

resolve conflict

parents 544325a7 ccd72ce2
...@@ -68,6 +68,7 @@ Task("Pack") ...@@ -68,6 +68,7 @@ Task("Pack")
{ {
Configuration = build.Configuration, Configuration = build.Configuration,
VersionSuffix = build.Version.Suffix, VersionSuffix = build.Version.Suffix,
IncludeSymbols = true,
OutputDirectory = "./artifacts/packages" OutputDirectory = "./artifacts/packages"
}; };
foreach (var project in build.ProjectFiles) foreach (var project in build.ProjectFiles)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<VersionMajor>2</VersionMajor> <VersionMajor>2</VersionMajor>
<VersionMinor>1</VersionMinor> <VersionMinor>1</VersionMinor>
<VersionPatch>0</VersionPatch> <VersionPatch>3</VersionPatch>
<VersionQuality></VersionQuality> <VersionQuality></VersionQuality>
<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix> <VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>
</PropertyGroup> </PropertyGroup>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.0.0" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.0.0" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
......
...@@ -8,13 +8,14 @@ ...@@ -8,13 +8,14 @@
<PackageTags>$(PackageTags);Kafka</PackageTags> <PackageTags>$(PackageTags);Kafka</PackageTags>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup>
<WarningsAsErrors>NU1605;NU1701</WarningsAsErrors> <WarningsAsErrors>NU1605;NU1701</WarningsAsErrors>
<NoWarn>NU1701</NoWarn> <NoWarn>NU1701;CS1591</NoWarn>
<DocumentationFile>bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.Kafka.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Confluent.Kafka" Version="0.11.2" /> <PackageReference Include="Confluent.Kafka" Version="0.11.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -24,7 +24,7 @@ namespace DotNetCore.CAP.Kafka ...@@ -24,7 +24,7 @@ namespace DotNetCore.CAP.Kafka
public event EventHandler<MessageContext> OnMessageReceived; public event EventHandler<MessageContext> OnMessageReceived;
public event EventHandler<string> OnError; public event EventHandler<LogMessageEventArgs> OnLog;
public void Subscribe(IEnumerable<string> topics) public void Subscribe(IEnumerable<string> topics)
{ {
...@@ -34,7 +34,6 @@ namespace DotNetCore.CAP.Kafka ...@@ -34,7 +34,6 @@ namespace DotNetCore.CAP.Kafka
if (_consumerClient == null) if (_consumerClient == null)
InitKafkaClient(); InitKafkaClient();
//_consumerClient.Assign(topics.Select(x=> new TopicPartition(x, 0)));
_consumerClient.Subscribe(topics); _consumerClient.Subscribe(topics);
} }
...@@ -55,7 +54,7 @@ namespace DotNetCore.CAP.Kafka ...@@ -55,7 +54,7 @@ namespace DotNetCore.CAP.Kafka
public void Reject() public void Reject()
{ {
// Ignore, Kafka will not commit offset when not commit. _consumerClient.Assign(_consumerClient.Assignment);
} }
public void Dispose() public void Dispose()
...@@ -76,12 +75,17 @@ namespace DotNetCore.CAP.Kafka ...@@ -76,12 +75,17 @@ namespace DotNetCore.CAP.Kafka
_consumerClient.OnError += ConsumerClient_OnError; _consumerClient.OnError += ConsumerClient_OnError;
} }
private void ConsumerClient_OnConsumeError(object sender, Message e) private void ConsumerClient_OnConsumeError(object sender, Message e)
{ {
var message = e.Deserialize<Null, string>(null, StringDeserializer); var message = e.Deserialize<Null, string>(null, StringDeserializer);
var logArgs = new LogMessageEventArgs
OnError?.Invoke(sender, $"An error occurred during consume the message; Topic:'{e.Topic}'," + {
$"Message:'{message.Value}', Reason:'{e.Error}'."); LogType = MqLogType.ConsumeError,
Reason = $"An error occurred during consume the message; Topic:'{e.Topic}'," +
$"Message:'{message.Value}', Reason:'{e.Error}'."
};
OnLog?.Invoke(sender, logArgs);
} }
private void ConsumerClient_OnMessage(object sender, Message<Null, string> e) private void ConsumerClient_OnMessage(object sender, Message<Null, string> e)
...@@ -98,7 +102,12 @@ namespace DotNetCore.CAP.Kafka ...@@ -98,7 +102,12 @@ namespace DotNetCore.CAP.Kafka
private void ConsumerClient_OnError(object sender, Error e) private void ConsumerClient_OnError(object sender, Error e)
{ {
OnError?.Invoke(sender, e.ToString()); var logArgs = new LogMessageEventArgs
{
LogType = MqLogType.ServerConnError,
Reason = e.ToString()
};
OnLog?.Invoke(sender, logArgs);
} }
#endregion private methods #endregion private methods
......
...@@ -62,14 +62,12 @@ namespace DotNetCore.CAP.MySql ...@@ -62,14 +62,12 @@ namespace DotNetCore.CAP.MySql
_logger.LogInformation("Published Message has been persisted in the database. name:" + message); _logger.LogInformation("Published Message has been persisted in the database. name:" + message);
} }
protected override Task ExecuteAsync(IDbConnection dbConnection, IDbTransaction dbTransaction, protected override async Task ExecuteAsync(IDbConnection dbConnection, IDbTransaction dbTransaction,
CapPublishedMessage message) CapPublishedMessage message)
{ {
dbConnection.ExecuteAsync(PrepareSql(), message, dbTransaction); await dbConnection.ExecuteAsync(PrepareSql(), message, dbTransaction);
_logger.LogInformation("Published Message has been persisted in the database. name:" + message); _logger.LogInformation("Published Message has been persisted in the database. name:" + message);
return Task.CompletedTask;
} }
#region private methods #region private methods
......
...@@ -8,11 +8,16 @@ ...@@ -8,11 +8,16 @@
<PackageTags>$(PackageTags);MySQL</PackageTags> <PackageTags>$(PackageTags);MySQL</PackageTags>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<DocumentationFile>bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.MySql.xml</DocumentationFile>
<NoWarn>1701;1702;1705;CS1591</NoWarn>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" /> <PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.1" />
<PackageReference Include="MySqlConnector" Version="0.28.2" /> <PackageReference Include="MySqlConnector" Version="0.34.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
using System; using Dapper;
using System.Data;
using System.Threading;
using Dapper;
using DotNetCore.CAP.Models; using DotNetCore.CAP.Models;
using MySql.Data.MySqlClient;
namespace DotNetCore.CAP.MySql namespace DotNetCore.CAP.MySql
{ {
public class MySqlFetchedMessage : IFetchedMessage public class MySqlFetchedMessage : IFetchedMessage
{ {
private static readonly TimeSpan KeepAliveInterval = TimeSpan.FromMinutes(1); private readonly MySqlOptions _options;
private readonly IDbConnection _connection; private readonly string _processId;
private readonly object _lockObject = new object();
private readonly Timer _timer;
private readonly IDbTransaction _transaction;
public MySqlFetchedMessage(int messageId, public MySqlFetchedMessage(int messageId, MessageType type, string processId, MySqlOptions options)
MessageType type,
IDbConnection connection,
IDbTransaction transaction)
{ {
MessageId = messageId; MessageId = messageId;
MessageType = type; MessageType = type;
_connection = connection;
_transaction = transaction; _processId = processId;
_timer = new Timer(ExecuteKeepAliveQuery, null, KeepAliveInterval, KeepAliveInterval); _options = options;
} }
public int MessageId { get; } public int MessageId { get; }
...@@ -32,43 +24,25 @@ namespace DotNetCore.CAP.MySql ...@@ -32,43 +24,25 @@ namespace DotNetCore.CAP.MySql
public void RemoveFromQueue() public void RemoveFromQueue()
{ {
lock (_lockObject) using (var connection = new MySqlConnection(_options.ConnectionString))
{ {
_transaction.Commit(); connection.Execute($"DELETE FROM `{_options.TableNamePrefix}.queue` WHERE `ProcessId`=@ProcessId"
, new { ProcessId = _processId });
} }
} }
public void Requeue() public void Requeue()
{ {
lock (_lockObject) using (var connection = new MySqlConnection(_options.ConnectionString))
{ {
_transaction.Rollback(); connection.Execute($"UPDATE `{_options.TableNamePrefix}.queue` SET `ProcessId`=NULL WHERE `ProcessId`=@ProcessId"
, new { ProcessId = _processId });
} }
} }
public void Dispose() public void Dispose()
{
lock (_lockObject)
{
_timer?.Dispose();
_transaction.Dispose();
_connection.Dispose();
}
}
private void ExecuteKeepAliveQuery(object obj)
{
lock (_lockObject)
{
try
{
_connection?.Execute("SELECT 1", _transaction);
}
catch
{ {
// ignored // ignored
} }
} }
}
}
} }
\ No newline at end of file
...@@ -53,7 +53,8 @@ namespace DotNetCore.CAP.MySql ...@@ -53,7 +53,8 @@ namespace DotNetCore.CAP.MySql
$@" $@"
CREATE TABLE IF NOT EXISTS `{prefix}.queue` ( CREATE TABLE IF NOT EXISTS `{prefix}.queue` (
`MessageId` int(11) NOT NULL, `MessageId` int(11) NOT NULL,
`MessageType` tinyint(4) NOT NULL `MessageType` tinyint(4) NOT NULL,
`ProcessId` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `{prefix}.received` ( CREATE TABLE IF NOT EXISTS `{prefix}.received` (
...@@ -62,8 +63,8 @@ CREATE TABLE IF NOT EXISTS `{prefix}.received` ( ...@@ -62,8 +63,8 @@ CREATE TABLE IF NOT EXISTS `{prefix}.received` (
`Group` varchar(200) DEFAULT NULL, `Group` varchar(200) DEFAULT NULL,
`Content` longtext, `Content` longtext,
`Retries` int(11) DEFAULT NULL, `Retries` int(11) DEFAULT NULL,
`Added` datetime(6) NOT NULL, `Added` datetime NOT NULL,
`ExpiresAt` datetime(6) DEFAULT NULL, `ExpiresAt` datetime DEFAULT NULL,
`StatusName` varchar(50) NOT NULL, `StatusName` varchar(50) NOT NULL,
PRIMARY KEY (`Id`) PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
...@@ -73,8 +74,8 @@ CREATE TABLE IF NOT EXISTS `{prefix}.published` ( ...@@ -73,8 +74,8 @@ CREATE TABLE IF NOT EXISTS `{prefix}.published` (
`Name` varchar(200) NOT NULL, `Name` varchar(200) NOT NULL,
`Content` longtext, `Content` longtext,
`Retries` int(11) DEFAULT NULL, `Retries` int(11) DEFAULT NULL,
`Added` datetime(6) NOT NULL, `Added` datetime NOT NULL,
`ExpiresAt` datetime(6) DEFAULT NULL, `ExpiresAt` datetime DEFAULT NULL,
`StatusName` varchar(40) NOT NULL, `StatusName` varchar(40) NOT NULL,
PRIMARY KEY (`Id`) PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;"; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dapper; using Dapper;
using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Infrastructure;
...@@ -42,14 +41,12 @@ namespace DotNetCore.CAP.MySql ...@@ -42,14 +41,12 @@ namespace DotNetCore.CAP.MySql
public Task<IFetchedMessage> FetchNextMessageAsync() public Task<IFetchedMessage> FetchNextMessageAsync()
{ {
var processId = ObjectId.GenerateNewStringId();
var sql = $@" var sql = $@"
SELECT `MessageId`,`MessageType` FROM `{_prefix}.queue` LIMIT 1 FOR UPDATE; UPDATE `{_prefix}.queue` SET `ProcessId`=@ProcessId WHERE `ProcessId` IS NULL LIMIT 1;
DELETE FROM `{_prefix}.queue` LIMIT 1;"; SELECT `MessageId`,`MessageType` FROM `{_prefix}.queue` WHERE `ProcessId`=@ProcessId;";
// var sql = $@"
//SELECT @MId:=`MessageId` as MessageId, @MType:=`MessageType` as MessageType FROM `{_prefix}.queue` LIMIT 1;
//DELETE FROM `{_prefix}.queue` where `MessageId` = @MId AND `MessageType`=@MType;";
return FetchNextMessageCoreAsync(sql); return FetchNextMessageCoreAsync(sql, processId);
} }
public async Task<CapPublishedMessage> GetNextPublishedMessageToBeEnqueuedAsync() public async Task<CapPublishedMessage> GetNextPublishedMessageToBeEnqueuedAsync()
...@@ -60,6 +57,7 @@ SELECT * FROM `{_prefix}.published` WHERE Id=LAST_INSERT_ID();"; ...@@ -60,6 +57,7 @@ SELECT * FROM `{_prefix}.published` WHERE Id=LAST_INSERT_ID();";
using (var connection = new MySqlConnection(Options.ConnectionString)) using (var connection = new MySqlConnection(Options.ConnectionString))
{ {
connection.Execute("SELECT LAST_INSERT_ID(0)");
return await connection.QueryFirstOrDefaultAsync<CapPublishedMessage>(sql); return await connection.QueryFirstOrDefaultAsync<CapPublishedMessage>(sql);
} }
} }
...@@ -105,6 +103,7 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();"; ...@@ -105,6 +103,7 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();";
using (var connection = new MySqlConnection(Options.ConnectionString)) using (var connection = new MySqlConnection(Options.ConnectionString))
{ {
connection.Execute("SELECT LAST_INSERT_ID(0)");
return await connection.QueryFirstOrDefaultAsync<CapReceivedMessage>(sql); return await connection.QueryFirstOrDefaultAsync<CapReceivedMessage>(sql);
} }
} }
...@@ -118,15 +117,10 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();"; ...@@ -118,15 +117,10 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();";
} }
} }
public void Dispose()
{
}
public bool ChangePublishedState(int messageId, string state) public bool ChangePublishedState(int messageId, string state)
{ {
var sql = var sql =
$"UPDATE `{_prefix}.published` SET `Retries`=`Retries`+1,`StatusName` = '{state}' WHERE `Id`={messageId}"; $"UPDATE `{_prefix}.published` SET `Retries`=`Retries`+1,`ExpiresAt`=NULL,`StatusName` = '{state}' WHERE `Id`={messageId}";
using (var connection = new MySqlConnection(Options.ConnectionString)) using (var connection = new MySqlConnection(Options.ConnectionString))
{ {
...@@ -137,7 +131,7 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();"; ...@@ -137,7 +131,7 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();";
public bool ChangeReceivedState(int messageId, string state) public bool ChangeReceivedState(int messageId, string state)
{ {
var sql = var sql =
$"UPDATE `{_prefix}.received` SET `Retries`=`Retries`+1,`StatusName` = '{state}' WHERE `Id`={messageId}"; $"UPDATE `{_prefix}.received` SET `Retries`=`Retries`+1,`ExpiresAt`=NULL,`StatusName` = '{state}' WHERE `Id`={messageId}";
using (var connection = new MySqlConnection(Options.ConnectionString)) using (var connection = new MySqlConnection(Options.ConnectionString))
{ {
...@@ -145,45 +139,22 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();"; ...@@ -145,45 +139,22 @@ SELECT * FROM `{_prefix}.received` WHERE Id=LAST_INSERT_ID();";
} }
} }
private async Task<IFetchedMessage> FetchNextMessageCoreAsync(string sql, object args = null) private async Task<IFetchedMessage> FetchNextMessageCoreAsync(string sql, string processId)
{
//here don't use `using` to dispose
var connection = new MySqlConnection(Options.ConnectionString);
await connection.OpenAsync();
var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
FetchedMessage fetchedMessage = null;
try
{
//fetchedMessage = await connection.QuerySingleOrDefaultAsync<FetchedMessage>(sql, args, transaction);
// An anomaly with unknown causes, sometimes QuerySingleOrDefaultAsync can't return expected result.
using (var reader = connection.ExecuteReader(sql, args, transaction))
{
while (reader.Read())
{
fetchedMessage = new FetchedMessage
{ {
MessageId = (int)reader.GetInt64(0), FetchedMessage fetchedMessage;
MessageType = (MessageType)reader.GetInt64(1) using (var connection = new MySqlConnection(Options.ConnectionString))
};
}
}
}
catch (MySqlException)
{ {
transaction.Dispose(); fetchedMessage = await connection.QuerySingleOrDefaultAsync<FetchedMessage>(sql, new { ProcessId = processId });
throw;
} }
if (fetchedMessage == null) if (fetchedMessage == null)
{
transaction.Rollback();
transaction.Dispose();
connection.Dispose();
return null; return null;
return new MySqlFetchedMessage(fetchedMessage.MessageId, fetchedMessage.MessageType, processId, Options);
} }
return new MySqlFetchedMessage(fetchedMessage.MessageId, fetchedMessage.MessageType, connection, public void Dispose()
transaction); {
} }
} }
} }
\ No newline at end of file
...@@ -46,7 +46,7 @@ namespace DotNetCore.CAP.MySql ...@@ -46,7 +46,7 @@ namespace DotNetCore.CAP.MySql
{ {
if (message == null) throw new ArgumentNullException(nameof(message)); if (message == null) throw new ArgumentNullException(nameof(message));
var sql = $"INSERT INTO `{_prefix}.queue` values(@MessageId,@MessageType);"; var sql = $"INSERT INTO `{_prefix}.queue`(`MessageId`,`MessageType`) values(@MessageId,@MessageType);";
_dbConnection.Execute(sql, new CapQueue {MessageId = message.Id, MessageType = MessageType.Publish}, _dbConnection.Execute(sql, new CapQueue {MessageId = message.Id, MessageType = MessageType.Publish},
_dbTransaction); _dbTransaction);
} }
...@@ -55,7 +55,7 @@ namespace DotNetCore.CAP.MySql ...@@ -55,7 +55,7 @@ namespace DotNetCore.CAP.MySql
{ {
if (message == null) throw new ArgumentNullException(nameof(message)); if (message == null) throw new ArgumentNullException(nameof(message));
var sql = $"INSERT INTO `{_prefix}.queue` values(@MessageId,@MessageType);"; var sql = $"INSERT INTO `{_prefix}.queue`(`MessageId`,`MessageType`) values(@MessageId,@MessageType);";
_dbConnection.Execute(sql, new CapQueue {MessageId = message.Id, MessageType = MessageType.Subscribe}, _dbConnection.Execute(sql, new CapQueue {MessageId = message.Id, MessageType = MessageType.Subscribe},
_dbTransaction); _dbTransaction);
} }
......
...@@ -64,14 +64,12 @@ namespace DotNetCore.CAP.PostgreSql ...@@ -64,14 +64,12 @@ namespace DotNetCore.CAP.PostgreSql
_logger.LogInformation("Published Message has been persisted in the database. name:" + message); _logger.LogInformation("Published Message has been persisted in the database. name:" + message);
} }
protected override Task ExecuteAsync(IDbConnection dbConnection, IDbTransaction dbTransaction, protected override async Task ExecuteAsync(IDbConnection dbConnection, IDbTransaction dbTransaction,
CapPublishedMessage message) CapPublishedMessage message)
{ {
dbConnection.ExecuteAsync(PrepareSql(), message, dbTransaction); await dbConnection.ExecuteAsync(PrepareSql(), message, dbTransaction);
_logger.LogInformation("Published Message has been persisted in the database. name:" + message); _logger.LogInformation("Published Message has been persisted in the database. name:" + message);
return Task.CompletedTask;
} }
#region private methods #region private methods
......
...@@ -8,11 +8,16 @@ ...@@ -8,11 +8,16 @@
<PackageTags>$(PackageTags);PostgreSQL</PackageTags> <PackageTags>$(PackageTags);PostgreSQL</PackageTags>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<DocumentationFile>bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.PostgreSql.xml</DocumentationFile>
<NoWarn>1701;1702;1705;CS1591</NoWarn>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" /> <PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.1" />
<PackageReference Include="Npgsql" Version="3.2.5" /> <PackageReference Include="Npgsql" Version="3.2.6" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -113,7 +113,7 @@ namespace DotNetCore.CAP.PostgreSql ...@@ -113,7 +113,7 @@ namespace DotNetCore.CAP.PostgreSql
public bool ChangePublishedState(int messageId, string state) public bool ChangePublishedState(int messageId, string state)
{ {
var sql = var sql =
$"UPDATE \"{Options.Schema}\".\"published\" SET \"Retries\"=\"Retries\"+1,\"StatusName\" = '{state}' WHERE \"Id\"={messageId}"; $"UPDATE \"{Options.Schema}\".\"published\" SET \"Retries\"=\"Retries\"+1,\"ExpiresAt\"=NULL,\"StatusName\" = '{state}' WHERE \"Id\"={messageId}";
using (var connection = new NpgsqlConnection(Options.ConnectionString)) using (var connection = new NpgsqlConnection(Options.ConnectionString))
{ {
...@@ -124,7 +124,7 @@ namespace DotNetCore.CAP.PostgreSql ...@@ -124,7 +124,7 @@ namespace DotNetCore.CAP.PostgreSql
public bool ChangeReceivedState(int messageId, string state) public bool ChangeReceivedState(int messageId, string state)
{ {
var sql = var sql =
$"UPDATE \"{Options.Schema}\".\"received\" SET \"Retries\"=\"Retries\"+1,\"StatusName\" = '{state}' WHERE \"Id\"={messageId}"; $"UPDATE \"{Options.Schema}\".\"received\" SET \"Retries\"=\"Retries\"+1,\"ExpiresAt\"=NULL,\"StatusName\" = '{state}' WHERE \"Id\"={messageId}";
using (var connection = new NpgsqlConnection(Options.ConnectionString)) using (var connection = new NpgsqlConnection(Options.ConnectionString))
{ {
...@@ -146,6 +146,7 @@ namespace DotNetCore.CAP.PostgreSql ...@@ -146,6 +146,7 @@ namespace DotNetCore.CAP.PostgreSql
catch (NpgsqlException) catch (NpgsqlException)
{ {
transaction.Dispose(); transaction.Dispose();
connection.Dispose();
throw; throw;
} }
......
...@@ -28,9 +28,9 @@ namespace DotNetCore.CAP ...@@ -28,9 +28,9 @@ namespace DotNetCore.CAP
public const string DefaultVHost = "/"; public const string DefaultVHost = "/";
/// <summary> /// <summary>
/// Default exchange name (value: "cap.default.topic"). /// Default exchange name (value: "cap.default.router").
/// </summary> /// </summary>
public const string DefaultExchangeName = "cap.default.topic"; public const string DefaultExchangeName = "cap.default.router";
/// <summary> The topic exchange type. </summary> /// <summary> The topic exchange type. </summary>
public const string ExchangeType = "topic"; public const string ExchangeType = "topic";
......
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
<PackageTags>$(PackageTags);RabbitMQ</PackageTags> <PackageTags>$(PackageTags);RabbitMQ</PackageTags>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<DocumentationFile>bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.RabbitMQ.xml</DocumentationFile>
<NoWarn>1701;1702;1705;CS1591</NoWarn>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RabbitMQ.Client" Version="5.0.1" /> <PackageReference Include="RabbitMQ.Client" Version="5.0.1" />
</ItemGroup> </ItemGroup>
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using RabbitMQ.Client; using RabbitMQ.Client;
using RabbitMQ.Client.Events; using RabbitMQ.Client.Events;
...@@ -15,6 +14,7 @@ namespace DotNetCore.CAP.RabbitMQ ...@@ -15,6 +14,7 @@ namespace DotNetCore.CAP.RabbitMQ
private readonly string _queueName; private readonly string _queueName;
private readonly RabbitMQOptions _rabbitMQOptions; private readonly RabbitMQOptions _rabbitMQOptions;
private IConnection _connection;
private IModel _channel; private IModel _channel;
private ulong _deliveryTag; private ulong _deliveryTag;
...@@ -32,7 +32,7 @@ namespace DotNetCore.CAP.RabbitMQ ...@@ -32,7 +32,7 @@ namespace DotNetCore.CAP.RabbitMQ
public event EventHandler<MessageContext> OnMessageReceived; public event EventHandler<MessageContext> OnMessageReceived;
public event EventHandler<string> OnError; public event EventHandler<LogMessageEventArgs> OnLog;
public void Subscribe(IEnumerable<string> topics) public void Subscribe(IEnumerable<string> topics)
{ {
...@@ -47,9 +47,18 @@ namespace DotNetCore.CAP.RabbitMQ ...@@ -47,9 +47,18 @@ namespace DotNetCore.CAP.RabbitMQ
var consumer = new EventingBasicConsumer(_channel); var consumer = new EventingBasicConsumer(_channel);
consumer.Received += OnConsumerReceived; consumer.Received += OnConsumerReceived;
consumer.Shutdown += OnConsumerShutdown; consumer.Shutdown += OnConsumerShutdown;
consumer.Registered += OnConsumerRegistered;
consumer.Unregistered += OnConsumerUnregistered;
consumer.ConsumerCancelled += OnConsumerConsumerCancelled;
_channel.BasicConsume(_queueName, false, consumer); _channel.BasicConsume(_queueName, false, consumer);
while (true) while (true)
Task.Delay(timeout, cancellationToken).GetAwaiter().GetResult(); {
cancellationToken.ThrowIfCancellationRequested();
cancellationToken.WaitHandle.WaitOne(timeout);
}
// ReSharper disable once FunctionNeverReturns
} }
public void Commit() public void Commit()
...@@ -65,13 +74,14 @@ namespace DotNetCore.CAP.RabbitMQ ...@@ -65,13 +74,14 @@ namespace DotNetCore.CAP.RabbitMQ
public void Dispose() public void Dispose()
{ {
_channel.Dispose(); _channel.Dispose();
_connection.Dispose();
} }
private void InitClient() private void InitClient()
{ {
var connection = _connectionChannelPool.GetConnection(); _connection = _connectionChannelPool.GetConnection();
_channel = connection.CreateModel(); _channel = _connection.CreateModel();
_channel.ExchangeDeclare( _channel.ExchangeDeclare(
_exchageName, _exchageName,
...@@ -84,6 +94,38 @@ namespace DotNetCore.CAP.RabbitMQ ...@@ -84,6 +94,38 @@ namespace DotNetCore.CAP.RabbitMQ
_channel.QueueDeclare(_queueName, true, false, false, arguments); _channel.QueueDeclare(_queueName, true, false, false, arguments);
} }
#region events
private void OnConsumerConsumerCancelled(object sender, ConsumerEventArgs e)
{
var args = new LogMessageEventArgs
{
LogType = MqLogType.ConsumerCancelled,
Reason = e.ConsumerTag
};
OnLog?.Invoke(sender, args);
}
private void OnConsumerUnregistered(object sender, ConsumerEventArgs e)
{
var args = new LogMessageEventArgs
{
LogType = MqLogType.ConsumerUnregistered,
Reason = e.ConsumerTag
};
OnLog?.Invoke(sender, args);
}
private void OnConsumerRegistered(object sender, ConsumerEventArgs e)
{
var args = new LogMessageEventArgs
{
LogType = MqLogType.ConsumerRegistered,
Reason = e.ConsumerTag
};
OnLog?.Invoke(sender, args);
}
private void OnConsumerReceived(object sender, BasicDeliverEventArgs e) private void OnConsumerReceived(object sender, BasicDeliverEventArgs e)
{ {
_deliveryTag = e.DeliveryTag; _deliveryTag = e.DeliveryTag;
...@@ -98,7 +140,14 @@ namespace DotNetCore.CAP.RabbitMQ ...@@ -98,7 +140,14 @@ namespace DotNetCore.CAP.RabbitMQ
private void OnConsumerShutdown(object sender, ShutdownEventArgs e) private void OnConsumerShutdown(object sender, ShutdownEventArgs e)
{ {
OnError?.Invoke(sender, e.Cause?.ToString()); var args = new LogMessageEventArgs
{
LogType = MqLogType.ConsumerShutdown,
Reason = e.ToString()
};
OnLog?.Invoke(sender, args);
} }
#endregion
} }
} }
\ No newline at end of file
...@@ -60,17 +60,15 @@ namespace DotNetCore.CAP.SqlServer ...@@ -60,17 +60,15 @@ namespace DotNetCore.CAP.SqlServer
{ {
dbConnection.Execute(PrepareSql(), message, dbTransaction); dbConnection.Execute(PrepareSql(), message, dbTransaction);
_logger.LogInformation("Published Message has been persisted in the database. name:" + message); _logger.LogInformation("published message has been persisted to the database. name:" + message);
} }
protected override Task ExecuteAsync(IDbConnection dbConnection, IDbTransaction dbTransaction, protected override async Task ExecuteAsync(IDbConnection dbConnection, IDbTransaction dbTransaction,
CapPublishedMessage message) CapPublishedMessage message)
{ {
dbConnection.ExecuteAsync(PrepareSql(), message, dbTransaction); await dbConnection.ExecuteAsync(PrepareSql(), message, dbTransaction);
_logger.LogInformation("Published Message has been persisted in the database. name:" + message); _logger.LogInformation("published message has been persisted to the database. name:" + message);
return Task.CompletedTask;
} }
#region private methods #region private methods
......
...@@ -8,11 +8,16 @@ ...@@ -8,11 +8,16 @@
<PackageTags>$(PackageTags);SQL Server</PackageTags> <PackageTags>$(PackageTags);SQL Server</PackageTags>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<DocumentationFile>bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.SqlServer.xml</DocumentationFile>
<NoWarn>1701;1702;1705;CS1591</NoWarn>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" /> <PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.1" />
<PackageReference Include="System.Data.SqlClient" Version="4.4.0" /> <PackageReference Include="System.Data.SqlClient" Version="4.4.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -68,19 +68,6 @@ OUTPUT DELETED.MessageId,DELETED.[MessageType];"; ...@@ -68,19 +68,6 @@ OUTPUT DELETED.MessageId,DELETED.[MessageType];";
} }
} }
public bool ChangePublishedState(int messageId, string state)
{
var sql =
$"UPDATE [{Options.Schema}].[Published] SET Retries=Retries+1,StatusName = '{state}' WHERE Id={messageId}";
using (var connection = new SqlConnection(Options.ConnectionString))
{
return connection.Execute(sql) > 0;
}
}
// CapReceivedMessage
public async Task StoreReceivedMessageAsync(CapReceivedMessage message) public async Task StoreReceivedMessageAsync(CapReceivedMessage message)
{ {
if (message == null) throw new ArgumentNullException(nameof(message)); if (message == null) throw new ArgumentNullException(nameof(message));
...@@ -124,10 +111,21 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; ...@@ -124,10 +111,21 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);";
} }
} }
public bool ChangePublishedState(int messageId, string state)
{
var sql =
$"UPDATE [{Options.Schema}].[Published] SET Retries=Retries+1,ExpiresAt=NULL,StatusName = '{state}' WHERE Id={messageId}";
using (var connection = new SqlConnection(Options.ConnectionString))
{
return connection.Execute(sql) > 0;
}
}
public bool ChangeReceivedState(int messageId, string state) public bool ChangeReceivedState(int messageId, string state)
{ {
var sql = var sql =
$"UPDATE [{Options.Schema}].[Received] SET Retries=Retries+1,StatusName = '{state}' WHERE Id={messageId}"; $"UPDATE [{Options.Schema}].[Received] SET Retries=Retries+1,ExpiresAt=NULL,StatusName = '{state}' WHERE Id={messageId}";
using (var connection = new SqlConnection(Options.ConnectionString)) using (var connection = new SqlConnection(Options.ConnectionString))
{ {
...@@ -153,6 +151,7 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; ...@@ -153,6 +151,7 @@ VALUES(@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);";
catch (SqlException) catch (SqlException)
{ {
transaction.Dispose(); transaction.Dispose();
connection.Dispose();
throw; throw;
} }
......
...@@ -123,7 +123,7 @@ namespace DotNetCore.CAP.Abstractions ...@@ -123,7 +123,7 @@ namespace DotNetCore.CAP.Abstractions
"If you are using the EntityFramework, you do not need to use this overloaded."); "If you are using the EntityFramework, you do not need to use this overloaded.");
} }
private Task PublishWithTransAsync(string name, string content) private async Task PublishWithTransAsync(string name, string content)
{ {
var message = new CapPublishedMessage var message = new CapPublishedMessage
{ {
...@@ -132,13 +132,11 @@ namespace DotNetCore.CAP.Abstractions ...@@ -132,13 +132,11 @@ namespace DotNetCore.CAP.Abstractions
StatusName = StatusName.Scheduled StatusName = StatusName.Scheduled
}; };
ExecuteAsync(DbConnection, DbTransaction, message); await ExecuteAsync(DbConnection, DbTransaction, message);
ClosedCap(); ClosedCap();
PublishQueuer.PulseEvent.Set(); PublishQueuer.PulseEvent.Set();
return Task.CompletedTask;
} }
private void PublishWithTrans(string name, string content) private void PublishWithTrans(string name, string content)
......
...@@ -20,9 +20,10 @@ namespace DotNetCore.CAP.Abstractions ...@@ -20,9 +20,10 @@ namespace DotNetCore.CAP.Abstractions
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
/// Default group name is CapOptions setting.(Assembly name)
/// kafka --> groups.id /// kafka --> groups.id
/// rabbit MQ --> queue.name /// rabbit MQ --> queue.name
/// </summary> /// </summary>
public string Group { get; set; } = "cap.default.group"; public string Group { get; set; }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection;
using DotNetCore.CAP.Models; using DotNetCore.CAP.Models;
namespace DotNetCore.CAP namespace DotNetCore.CAP
...@@ -34,6 +35,7 @@ namespace DotNetCore.CAP ...@@ -34,6 +35,7 @@ namespace DotNetCore.CAP
/// </summary> /// </summary>
public const int DefaultFailedRetryCount = 100; public const int DefaultFailedRetryCount = 100;
public CapOptions() public CapOptions()
{ {
PollingDelay = DefaultPollingDelay; PollingDelay = DefaultPollingDelay;
...@@ -42,10 +44,16 @@ namespace DotNetCore.CAP ...@@ -42,10 +44,16 @@ namespace DotNetCore.CAP
FailedRetryInterval = DefaultFailedMessageWaitingInterval; FailedRetryInterval = DefaultFailedMessageWaitingInterval;
FailedRetryCount = DefaultFailedRetryCount; FailedRetryCount = DefaultFailedRetryCount;
Extensions = new List<ICapOptionsExtension>(); Extensions = new List<ICapOptionsExtension>();
DefaultGroup = "cap.queue." + Assembly.GetEntryAssembly().GetName().Name.ToLower();
} }
internal IList<ICapOptionsExtension> Extensions { get; } internal IList<ICapOptionsExtension> Extensions { get; }
/// <summary>
/// Subscriber default group name. kafka-->group name. rabbitmq --> queue name.
/// </summary>
public string DefaultGroup { get; set; }
/// <summary> /// <summary>
/// Producer job polling delay time. /// Producer job polling delay time.
/// Default is 15 sec. /// Default is 15 sec.
......
...@@ -371,7 +371,7 @@ ...@@ -371,7 +371,7 @@
receivedSucceeded, receivedSucceeded,
receivedFailed, receivedFailed,
receivedSucceededStr, receivedSucceededStr,
receivedFailedStr, receivedFailedStr
); );
$(window).resize(function() { $(window).resize(function() {
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
<AssemblyName>DotNetCore.CAP</AssemblyName> <AssemblyName>DotNetCore.CAP</AssemblyName>
<PackageTags>$(PackageTags);</PackageTags> <PackageTags>$(PackageTags);</PackageTags>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<DocumentationFile>bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.xml</DocumentationFile>
<NoWarn>1701;1702;1705;CS1591</NoWarn>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="Dashboard\Content\css\bootstrap.min.css" /> <None Remove="Dashboard\Content\css\bootstrap.min.css" />
<None Remove="Dashboard\Content\css\jsonview.min.css" /> <None Remove="Dashboard\Content\css\jsonview.min.css" />
......
...@@ -33,6 +33,6 @@ namespace DotNetCore.CAP ...@@ -33,6 +33,6 @@ namespace DotNetCore.CAP
event EventHandler<MessageContext> OnMessageReceived; event EventHandler<MessageContext> OnMessageReceived;
event EventHandler<string> OnError; event EventHandler<LogMessageEventArgs> OnLog;
} }
} }
\ No newline at end of file
...@@ -23,6 +23,7 @@ namespace DotNetCore.CAP ...@@ -23,6 +23,7 @@ namespace DotNetCore.CAP
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private Task _compositeTask; private Task _compositeTask;
private bool _disposed; private bool _disposed;
public ConsumerHandler( public ConsumerHandler(
...@@ -54,6 +55,7 @@ namespace DotNetCore.CAP ...@@ -54,6 +55,7 @@ namespace DotNetCore.CAP
client.Listening(_pollingDelay, _cts.Token); client.Listening(_pollingDelay, _cts.Token);
} }
}, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); }, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
_compositeTask = Task.CompletedTask; _compositeTask = Task.CompletedTask;
} }
...@@ -62,13 +64,10 @@ namespace DotNetCore.CAP ...@@ -62,13 +64,10 @@ namespace DotNetCore.CAP
if (_disposed) if (_disposed)
return; return;
_disposed = true; _disposed = true;
_logger.ServerShuttingDown();
_cts.Cancel(); _cts.Cancel();
try try
{ {
_compositeTask.Wait(TimeSpan.FromSeconds(10)); _compositeTask.Wait(TimeSpan.FromSeconds(2));
} }
catch (AggregateException ex) catch (AggregateException ex)
{ {
...@@ -105,7 +104,34 @@ namespace DotNetCore.CAP ...@@ -105,7 +104,34 @@ namespace DotNetCore.CAP
Pulse(); Pulse();
}; };
client.OnError += (sender, reason) => { _logger.MessageQueueError(reason); }; client.OnLog += WriteLog;
}
private void WriteLog(object sender, LogMessageEventArgs logmsg)
{
switch (logmsg.LogType)
{
case MqLogType.ConsumerCancelled:
_logger.LogWarning("RabbitMQ consumer cancelled. reason: " + logmsg.Reason);
break;
case MqLogType.ConsumerRegistered:
_logger.LogInformation("RabbitMQ consumer registered. " + logmsg.Reason);
break;
case MqLogType.ConsumerUnregistered:
_logger.LogWarning("RabbitMQ consumer unregistered. reason: " + logmsg.Reason);
break;
case MqLogType.ConsumerShutdown:
_logger.LogWarning("RabbitMQ consumer shutdown. reason:" + logmsg.Reason);
break;
case MqLogType.ConsumeError:
_logger.LogError("Kakfa client consume error. reason:" + logmsg.Reason);
break;
case MqLogType.ServerConnError:
_logger.LogCritical("Kafka server connection error. reason:" + logmsg.Reason);
break;
default:
throw new ArgumentOutOfRangeException();
}
} }
private static void StoreMessage(IServiceScope serviceScope, MessageContext messageContext) private static void StoreMessage(IServiceScope serviceScope, MessageContext messageContext)
......
...@@ -76,7 +76,7 @@ namespace DotNetCore.CAP ...@@ -76,7 +76,7 @@ namespace DotNetCore.CAP
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.ExceptionOccuredWhileExecuting(message?.Name, ex); _logger.ExceptionOccuredWhileExecuting(message.Name, ex);
fetched.Requeue(); fetched.Requeue();
...@@ -89,7 +89,7 @@ namespace DotNetCore.CAP ...@@ -89,7 +89,7 @@ namespace DotNetCore.CAP
IState newState; IState newState;
if (!result.Succeeded) if (!result.Succeeded)
{ {
var shouldRetry = UpdateMessageForRetryAsync(message); var shouldRetry = UpdateMessageForRetry(message);
if (shouldRetry) if (shouldRetry)
{ {
newState = new ScheduledState(); newState = new ScheduledState();
...@@ -109,7 +109,7 @@ namespace DotNetCore.CAP ...@@ -109,7 +109,7 @@ namespace DotNetCore.CAP
return newState; return newState;
} }
private static bool UpdateMessageForRetryAsync(CapReceivedMessage message) private static bool UpdateMessageForRetry(CapReceivedMessage message)
{ {
var retryBehavior = RetryBehavior.DefaultRetry; var retryBehavior = RetryBehavior.DefaultRetry;
......
...@@ -14,18 +14,21 @@ namespace DotNetCore.CAP.Internal ...@@ -14,18 +14,21 @@ namespace DotNetCore.CAP.Internal
/// </summary> /// </summary>
internal class DefaultConsumerServiceSelector : IConsumerServiceSelector internal class DefaultConsumerServiceSelector : IConsumerServiceSelector
{ {
private readonly CapOptions _capOptions;
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
/// <summary> /// <summary>
/// Creates a new <see cref="DefaultConsumerServiceSelector" />. /// Creates a new <see cref="DefaultConsumerServiceSelector" />.
/// </summary> /// </summary>
public DefaultConsumerServiceSelector(IServiceProvider serviceProvider) public DefaultConsumerServiceSelector(IServiceProvider serviceProvider, CapOptions capOptions)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_capOptions = capOptions;
} }
/// <summary> /// <summary>
/// Selects the best <see cref="ConsumerExecutorDescriptor" /> candidate from <paramref name="executeDescriptor" /> for the /// Selects the best <see cref="ConsumerExecutorDescriptor" /> candidate from <paramref name="executeDescriptor" /> for
/// the
/// current message associated. /// current message associated.
/// </summary> /// </summary>
public ConsumerExecutorDescriptor SelectBestCandidate(string key, public ConsumerExecutorDescriptor SelectBestCandidate(string key,
...@@ -45,7 +48,7 @@ namespace DotNetCore.CAP.Internal ...@@ -45,7 +48,7 @@ namespace DotNetCore.CAP.Internal
return executorDescriptorList; return executorDescriptorList;
} }
private static IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes( private IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes(
IServiceProvider provider) IServiceProvider provider)
{ {
var executorDescriptorList = new List<ConsumerExecutorDescriptor>(); var executorDescriptorList = new List<ConsumerExecutorDescriptor>();
...@@ -66,7 +69,7 @@ namespace DotNetCore.CAP.Internal ...@@ -66,7 +69,7 @@ namespace DotNetCore.CAP.Internal
} }
} }
private static IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromControllerTypes() private IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromControllerTypes()
{ {
var executorDescriptorList = new List<ConsumerExecutorDescriptor>(); var executorDescriptorList = new List<ConsumerExecutorDescriptor>();
...@@ -81,20 +84,23 @@ namespace DotNetCore.CAP.Internal ...@@ -81,20 +84,23 @@ namespace DotNetCore.CAP.Internal
return executorDescriptorList; return executorDescriptorList;
} }
private static IEnumerable<ConsumerExecutorDescriptor> GetTopicAttributesDescription(TypeInfo typeInfo) private IEnumerable<ConsumerExecutorDescriptor> GetTopicAttributesDescription(TypeInfo typeInfo)
{ {
foreach (var method in typeInfo.DeclaredMethods) foreach (var method in typeInfo.DeclaredMethods)
{ {
var topicAttr = method.GetCustomAttributes<TopicAttribute>(true); var topicAttr = method.GetCustomAttributes<TopicAttribute>(true);
var topicAttributes = topicAttr as IList<TopicAttribute> ?? topicAttr.ToList(); var topicAttributes = topicAttr as IList<TopicAttribute> ?? topicAttr.ToList();
if (!topicAttributes.Any()) continue; if (!topicAttributes.Any()) continue;
foreach (var attr in topicAttributes) foreach (var attr in topicAttributes)
{
if (attr.Group == null)
attr.Group = _capOptions.DefaultGroup;
yield return InitDescriptor(attr, method, typeInfo); yield return InitDescriptor(attr, method, typeInfo);
} }
} }
}
private static ConsumerExecutorDescriptor InitDescriptor( private static ConsumerExecutorDescriptor InitDescriptor(
TopicAttribute attr, TopicAttribute attr,
......
...@@ -28,22 +28,18 @@ namespace DotNetCore.CAP.Internal ...@@ -28,22 +28,18 @@ namespace DotNetCore.CAP.Internal
public async Task<OperateResult> ExecuteAsync(CapReceivedMessage receivedMessage) public async Task<OperateResult> ExecuteAsync(CapReceivedMessage receivedMessage)
{ {
try if (!_selector.TryGetTopicExector(receivedMessage.Name, receivedMessage.Group,
{ out var executor))
var executeDescriptorGroup = _selector.GetTopicExector(receivedMessage.Name);
if (!executeDescriptorGroup.ContainsKey(receivedMessage.Group))
{ {
var error = $"Topic:{receivedMessage.Name}, can not be found subscriber method."; var error = "message can not be found subscriber. Message:" + receivedMessage;
error += "\r\n see: https://github.com/dotnetcore/CAP/issues/63";
throw new SubscriberNotFoundException(error); throw new SubscriberNotFoundException(error);
} }
// If there are multiple consumers in the same group, we will take the first var consumerContext = new ConsumerContext(executor, receivedMessage.ToMessageContext());
var executeDescriptor = executeDescriptorGroup[receivedMessage.Group][0]; try
var consumerContext = new ConsumerContext(executeDescriptor, receivedMessage.ToMessageContext()); {
var ret = await Invoker.InvokeAsync(consumerContext); var ret = await Invoker.InvokeAsync(consumerContext);
if (!string.IsNullOrEmpty(ret.CallbackName)) if (!string.IsNullOrEmpty(ret.CallbackName))
await _callbackMessageSender.SendAsync(ret.MessageId, ret.CallbackName, ret.Result); await _callbackMessageSender.SendAsync(ret.MessageId, ret.CallbackName, ret.Result);
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using DotNetCore.CAP.Abstractions;
namespace DotNetCore.CAP.Internal namespace DotNetCore.CAP.Internal
{ {
internal class MethodMatcherCache internal class MethodMatcherCache
{ {
private readonly IConsumerServiceSelector _selector; private readonly IConsumerServiceSelector _selector;
private List<string> _allTopics;
public MethodMatcherCache(IConsumerServiceSelector selector) public MethodMatcherCache(IConsumerServiceSelector selector)
{ {
...@@ -54,5 +54,50 @@ namespace DotNetCore.CAP.Internal ...@@ -54,5 +54,50 @@ namespace DotNetCore.CAP.Internal
} }
return dic; return dic;
} }
/// <summary>
/// Attempts to get the topic exector associated with the specified topic name and group name from the <see cref="Entries"/>.
/// </summary>
/// <param name="topicName">The topic name of the value to get.</param>
/// <param name="groupName">The group name of the value to get.</param>
/// <param name="matchTopic">topic exector of the value.</param>
/// <returns>true if the key was found, otherwise false. </returns>
public bool TryGetTopicExector(string topicName, string groupName,
out ConsumerExecutorDescriptor matchTopic)
{
if (Entries == null)
throw new ArgumentNullException(nameof(Entries));
matchTopic = null;
if (Entries.TryGetValue(groupName, out var groupMatchTopics))
{
matchTopic = groupMatchTopics.FirstOrDefault(x => x.Attribute.Name == topicName);
return matchTopic != null;
}
return false;
}
/// <summary>
/// Get all subscribe topics name.
/// </summary>
public IEnumerable<string> GetSubscribeTopics()
{
if (_allTopics != null)
{
return _allTopics;
}
if (Entries == null)
throw new ArgumentNullException(nameof(Entries));
_allTopics = new List<string>();
foreach (var descriptors in Entries.Values)
{
_allTopics.AddRange(descriptors.Select(x => x.Attribute.Name));
}
return _allTopics;
}
} }
} }
\ No newline at end of file
...@@ -37,7 +37,7 @@ namespace DotNetCore.CAP ...@@ -37,7 +37,7 @@ namespace DotNetCore.CAP
"Starting the processors throw an exception."); "Starting the processors throw an exception.");
_serverShuttingDown = LoggerMessage.Define( _serverShuttingDown = LoggerMessage.Define(
LogLevel.Debug, LogLevel.Information,
2, 2,
"Shutting down the processing server..."); "Shutting down the processing server...");
......
...@@ -47,7 +47,7 @@ namespace DotNetCore.CAP.Models ...@@ -47,7 +47,7 @@ namespace DotNetCore.CAP.Models
public override string ToString() public override string ToString()
{ {
return "name:" + Name + ", content:" + Content; return "name:" + Name + ", group:" + Group + ", content:" + Content;
} }
} }
} }
\ No newline at end of file
using System;
namespace DotNetCore.CAP
{
public enum MqLogType
{
//RabbitMQ
ConsumerCancelled,
ConsumerRegistered,
ConsumerUnregistered,
ConsumerShutdown,
//Kafka
ConsumeError,
ServerConnError
}
public class LogMessageEventArgs : EventArgs
{
public string Reason { get; set; }
public MqLogType LogType { get; set; }
}
}
...@@ -14,14 +14,14 @@ ...@@ -14,14 +14,14 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" /> <PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20170810-02" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="MySqlConnector" Version="0.28.2" /> <PackageReference Include="MySqlConnector" Version="0.34.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.0" /> <PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
<PackageReference Include="Moq" Version="4.7.137" /> <PackageReference Include="Moq" Version="4.8.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
......
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" /> <PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20170810-02" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="Npgsql" Version="3.2.5" /> <PackageReference Include="Npgsql" Version="3.2.6" />
<PackageReference Include="xunit" Version="2.3.0" /> <PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -11,14 +11,14 @@ ...@@ -11,14 +11,14 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="1.50.2" /> <PackageReference Include="Dapper" Version="1.50.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20170810-02" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.4.0" /> <PackageReference Include="System.Data.SqlClient" Version="4.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.0" /> <PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
<PackageReference Include="Moq" Version="4.7.137" /> <PackageReference Include="Moq" Version="4.8.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
......
...@@ -8,13 +8,13 @@ ...@@ -8,13 +8,13 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20170810-02" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="System.Data.Common" Version="4.3.0" /> <PackageReference Include="System.Data.Common" Version="4.3.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.0" /> <PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
<PackageReference Include="Moq" Version="4.7.137" /> <PackageReference Include="Moq" Version="4.8.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
</ItemGroup> </ItemGroup>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment