From fb6943e8475e5f1847c96b5b337d27e4a56f9d90 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 8 Jan 2019 09:42:39 +0800 Subject: [PATCH] release 2.4.2 (#272) * update version to 2.4.0 * Add version options to config file. * update resource * add message version support for dashboard * add message version support for dashboard * Support using version to isolate messages. #220 * update mongo unit tests * update unit tests * update unit tests * Set default versions for consumer groups * solve the problem of issue#181 (#237) * Issue#235 (#238) * solve the problem of issue#181 * solve the problem of issue#235 * refactor * Fix the message persistence bug. #240 * using new CamelCaseNamingStrategy * update packages to .net core 2.2 * update test framework to netcoreapp2.2 * Update .travis.yml * update TargetFramework * Exclude build samples project * update version to 2.4.1 * add samples project to sln for build * update version to 2.4.2 * Fixed PostgreSql version isolation feature bug. (#256) * Fixed spelling errors * modify cap publish Message to rabbitmq slow (#261) * Startup the CAP with the BackgroundService. #265 * update samples * Fixed SQL query bug. #266 * update travis ci config * update travis ci config * adjust dashboard table column width * adjust the consumer execution time to milliseconds --- .travis.yml | 21 +++--- build/version.props | 2 +- .../Controllers/ValuesController.cs | 2 +- .../Sample.RabbitMQ.MongoDB.csproj | 1 + samples/Sample.RabbitMQ.MongoDB/Startup.cs | 11 +-- .../Sample.RabbitMQ.MongoDB/appsettings.json | 6 +- .../IMonitoringApi.MySql.cs | 2 +- .../ICapPublisher.PostgreSql.cs | 2 +- .../IMonitoringApi.SqlServer.cs | 2 +- .../CAP.AppBuilderExtensions.cs | 9 +-- .../CAP.ServiceCollectionExtensions.cs | 5 +- .../Dashboard/Pages/PublishedPage.cshtml | 2 +- .../Pages/PublishedPage.generated.cs | 2 +- .../Dashboard/Pages/ReceivedPage.cshtml | 2 +- .../Dashboard/Pages/ReceivedPage.generated.cs | 2 +- src/DotNetCore.CAP/IBootstrapper.Default.cs | 69 ++++++------------- src/DotNetCore.CAP/IBootstrapper.cs | 3 +- .../IPublishMessageSender.Base.cs | 25 ++++--- .../ISubscribeExecutor.Default.cs | 4 +- .../Internal/LoggerExtensions.cs | 4 +- .../Internal/MethodMatcherCache.cs | 6 +- 21 files changed, 81 insertions(+), 101 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6582e7fd5..acb2d1c5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,22 @@ language: csharp sudo: required -dist: trusty +dist: xenial solution: CAP.sln -dotnet: 2.2.100 +dotnet: 2.2 mono: none -matrix: - include: - - os: linux - dist: trusty # Ubuntu 14.04 - sudo: required - - os: osx - osx_image: xcode8.3 # macOS 10.12 +#matrix: +# include: +# - dotnet: 2.2 +# - os: linux +# dist: trusty # Ubuntu 14.04 +# sudo: required +# - os: osx +# osx_image: xcode8.3 # macOS 10.12 # Run the build script script: - dotnet --info - dotnet restore CAP.sln - dotnet build CAP.sln - - dotnet test test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj + - dotnet test test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj \ No newline at end of file diff --git a/build/version.props b/build/version.props index 67b0d9f41..7932a0e24 100644 --- a/build/version.props +++ b/build/version.props @@ -2,7 +2,7 @@ 2 4 - 1 + 2 $(VersionMajor).$(VersionMinor).$(VersionPatch) diff --git a/samples/Sample.RabbitMQ.MongoDB/Controllers/ValuesController.cs b/samples/Sample.RabbitMQ.MongoDB/Controllers/ValuesController.cs index 067b6d469..7c064a971 100644 --- a/samples/Sample.RabbitMQ.MongoDB/Controllers/ValuesController.cs +++ b/samples/Sample.RabbitMQ.MongoDB/Controllers/ValuesController.cs @@ -22,7 +22,7 @@ public ValuesController(IMongoClient client, ICapPublisher capBus) [Route("~/without/transaction")] public IActionResult WithoutTransaction() { - _capBus.Publish("sample.rabbitmq.mongodb", DateTime.Now); + _capBus.PublishAsync("sample.rabbitmq.mongodb", DateTime.Now); return Ok(); } diff --git a/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj b/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj index eebde0cda..172568850 100644 --- a/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj +++ b/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj @@ -2,6 +2,7 @@ netcoreapp2.2 + 7.1 diff --git a/samples/Sample.RabbitMQ.MongoDB/Startup.cs b/samples/Sample.RabbitMQ.MongoDB/Startup.cs index 2ef0da212..da07bd386 100644 --- a/samples/Sample.RabbitMQ.MongoDB/Startup.cs +++ b/samples/Sample.RabbitMQ.MongoDB/Startup.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Builder; +using System; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; @@ -18,14 +19,14 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { - services.AddSingleton(new MongoClient("mongodb://192.168.10.110:27017,192.168.10.110:27018,192.168.10.110:27019/?replicaSet=rs0")); + services.AddSingleton(new MongoClient(Configuration.GetConnectionString("MongoDB"))); services.AddCap(x => { - x.UseMongoDB("mongodb://192.168.10.110:27017,192.168.10.110:27018,192.168.10.110:27019/?replicaSet=rs0"); - x.UseRabbitMQ("localhost"); + x.UseMongoDB(Configuration.GetConnectionString("MongoDB")); + x.UseRabbitMQ("192.168.2.120"); x.UseDashboard(); }); - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); + services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) diff --git a/samples/Sample.RabbitMQ.MongoDB/appsettings.json b/samples/Sample.RabbitMQ.MongoDB/appsettings.json index 5707bfbd7..49a455fac 100644 --- a/samples/Sample.RabbitMQ.MongoDB/appsettings.json +++ b/samples/Sample.RabbitMQ.MongoDB/appsettings.json @@ -1,12 +1,12 @@ { "Logging": { "LogLevel": { - "Default": "Warning" + "Default": "Debug" } }, "AllowedHosts": "*", "ConnectionStrings": { - "MongoDB": "mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0" + "MongoDB": "mongodb://192.168.2.120:27017,192.168.2.120:27018,192.168.2.120:27019/?replicaSet=rs0" }, "RabbitMQ": { "HostName": "localhost", @@ -14,4 +14,4 @@ "UserName": "", "Password": "" } -} \ No newline at end of file +} diff --git a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs index a67e8d6ea..353a279fd 100644 --- a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs @@ -80,7 +80,7 @@ public IList Messages(MessageQueryDto queryDto) if (!string.IsNullOrEmpty(queryDto.Group)) { - where += " and Group=@Group"; + where += " and `Group`=@Group"; } if (!string.IsNullOrEmpty(queryDto.Content)) diff --git a/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs index bba6dadd2..95c0c63b1 100644 --- a/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs @@ -55,7 +55,7 @@ protected override async Task ExecuteAsync(CapPublishedMessage message, ICapTran private string PrepareSql() { return - $"INSERT INTO \"{_options.Schema}\".\"published\" (\"Id\",\"Version\",\"Name\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")VALUES(@Id,@Version,@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + $"INSERT INTO \"{_options.Schema}\".\"published\" (\"Id\",\"Version\",\"Name\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")VALUES(@Id,'{_options.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; } private IDbConnection InitDbConnection() diff --git a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs index 38c43180d..e3e49af91 100644 --- a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs @@ -81,7 +81,7 @@ public IList Messages(MessageQueryDto queryDto) if (!string.IsNullOrEmpty(queryDto.Group)) { - where += " and group=@Group"; + where += " and [group]=@Group"; } if (!string.IsNullOrEmpty(queryDto.Content)) diff --git a/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs b/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs index 53c048c79..e56d50f03 100644 --- a/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs +++ b/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs @@ -20,7 +20,7 @@ internal static class AppBuilderExtensions /// /// The instance this method extends. /// The instance this method extends. - public static IApplicationBuilder UseCap(this IApplicationBuilder app) + public static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app) { if (app == null) { @@ -30,10 +30,7 @@ public static IApplicationBuilder UseCap(this IApplicationBuilder app) CheckRequirement(app); var provider = app.ApplicationServices; - - var bootstrapper = provider.GetRequiredService(); - bootstrapper.BootstrapAsync(); - + if (provider.GetService() != null) { if (provider.GetService() != null) @@ -78,7 +75,7 @@ public Action Configure(Action next) { return app => { - app.UseCap(); + app.UseCapDashboard(); next(app); }; diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 9abf3f7ac..4e791723e 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection @@ -48,10 +49,9 @@ public static CapBuilder AddCap(this IServiceCollection services, Action(); services.TryAddSingleton(); - //Bootstrapper and Processors + //Processors services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); - services.TryAddSingleton(); services.TryAddSingleton(); //Queue's message processor @@ -72,6 +72,7 @@ public static CapBuilder AddCap(this IServiceCollection services, Action(); services.AddTransient(); return new CapBuilder(services); diff --git a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cshtml b/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cshtml index d71b8a63b..2d7608929 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cshtml +++ b/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cshtml @@ -77,7 +77,7 @@ - diff --git a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.generated.cs b/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.generated.cs index f93fa89a2..4d8a578ce 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.generated.cs +++ b/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.generated.cs @@ -264,7 +264,7 @@ protected override void Execute()
+ @Strings.Common_Id
-
+ "); diff --git a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cshtml b/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cshtml index 01dcaade7..f063f7a78 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cshtml +++ b/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cshtml @@ -82,7 +82,7 @@ - diff --git a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.generated.cs b/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.generated.cs index 8f34929a1..ae3ea1fa6 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.generated.cs +++ b/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.generated.cs @@ -289,7 +289,7 @@ protected override void Execute()
+ @Strings.Common_Id
-
+ "); diff --git a/src/DotNetCore.CAP/IBootstrapper.Default.cs b/src/DotNetCore.CAP/IBootstrapper.Default.cs index 9af8f2e04..776970a0f 100644 --- a/src/DotNetCore.CAP/IBootstrapper.Default.cs +++ b/src/DotNetCore.CAP/IBootstrapper.Default.cs @@ -5,89 +5,59 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP { - /// /// /// Default implement of . /// - internal class DefaultBootstrapper : IBootstrapper + internal class DefaultBootstrapper : BackgroundService, IBootstrapper { - private readonly IApplicationLifetime _appLifetime; - private readonly CancellationTokenSource _cts; - private readonly CancellationTokenRegistration _ctsRegistration; private readonly ILogger _logger; - private Task _bootstrappingTask; public DefaultBootstrapper( ILogger logger, IStorage storage, - IApplicationLifetime appLifetime, IEnumerable processors) { _logger = logger; - _appLifetime = appLifetime; Storage = storage; Processors = processors; - - _cts = new CancellationTokenSource(); - _ctsRegistration = appLifetime.ApplicationStopping.Register(() => - { - _cts.Cancel(); - try - { - _bootstrappingTask?.GetAwaiter().GetResult(); - } - catch (OperationCanceledException ex) - { - _logger.ExpectedOperationCanceledException(ex); - } - }); } private IStorage Storage { get; } private IEnumerable Processors { get; } - public Task BootstrapAsync() - { - return _bootstrappingTask = BootstrapTaskAsync(); - } - - private async Task BootstrapTaskAsync() + public async Task BootstrapAsync(CancellationToken stoppingToken) { - _logger.LogInformation("### CAP starting..."); + _logger.LogDebug("### CAP background task is starting."); - await Storage.InitializeAsync(_cts.Token); + await Storage.InitializeAsync(stoppingToken); - if (_cts.IsCancellationRequested) + stoppingToken.Register(() => { - return; - } + _logger.LogDebug("### CAP background task is stopping."); - _appLifetime.ApplicationStopping.Register(() => - { foreach (var item in Processors) { - item.Dispose(); + try + { + item.Dispose(); + } + catch (OperationCanceledException ex) + { + _logger.ExpectedOperationCanceledException(ex); + } } }); - - if (_cts.IsCancellationRequested) - { - return; - } - + await BootstrapCoreAsync(); - _ctsRegistration.Dispose(); - _cts.Dispose(); - _logger.LogInformation("### CAP started!"); - } + } protected virtual Task BootstrapCoreAsync() { @@ -105,5 +75,10 @@ protected virtual Task BootstrapCoreAsync() return Task.CompletedTask; } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await BootstrapAsync(stoppingToken); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IBootstrapper.cs b/src/DotNetCore.CAP/IBootstrapper.cs index 9da162795..b781c5552 100644 --- a/src/DotNetCore.CAP/IBootstrapper.cs +++ b/src/DotNetCore.CAP/IBootstrapper.cs @@ -1,6 +1,7 @@ // 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; using System.Threading.Tasks; namespace DotNetCore.CAP @@ -10,6 +11,6 @@ namespace DotNetCore.CAP /// public interface IBootstrapper { - Task BootstrapAsync(); + Task BootstrapAsync(CancellationToken stoppingToken); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IPublishMessageSender.Base.cs b/src/DotNetCore.CAP/IPublishMessageSender.Base.cs index 45292ab6d..45d146d3b 100644 --- a/src/DotNetCore.CAP/IPublishMessageSender.Base.cs +++ b/src/DotNetCore.CAP/IPublishMessageSender.Base.cs @@ -44,20 +44,23 @@ protected BasePublishMessageSender( public async Task SendAsync(CapPublishedMessage message) { - bool retry; - OperateResult result; - do + return await Task.Run(async () => { - var executedResult = await SendWithoutRetryAsync(message); - result = executedResult.Item2; - if (result == OperateResult.Success) + bool retry; + OperateResult result; + do { - return result; - } - retry = executedResult.Item1; - } while (retry); + var executedResult = await SendWithoutRetryAsync(message); + result = executedResult.Item2; + if (result == OperateResult.Success) + { + return result; + } + retry = executedResult.Item1; + } while (retry); - return result; + return result; + }); } private async Task<(bool, OperateResult)> SendWithoutRetryAsync(CapPublishedMessage message) diff --git a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs index 84a1dca25..59109891a 100644 --- a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs +++ b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs @@ -89,7 +89,7 @@ public async Task ExecuteAsync(CapReceivedMessage message) await SetSuccessfulState(message); - _logger.ConsumerExecuted(sp.Elapsed.TotalSeconds); + _logger.ConsumerExecuted(sp.Elapsed.TotalMilliseconds); return (false, OperateResult.Success); } @@ -161,7 +161,7 @@ private static void AddErrorReasonToContent(CapReceivedMessage message, Exceptio private async Task InvokeConsumerMethodAsync(CapReceivedMessage receivedMessage) { - if (!_selector.TryGetTopicExector(receivedMessage.Name, receivedMessage.Group, + if (!_selector.TryGetTopicExecutor(receivedMessage.Name, receivedMessage.Group, out var executor)) { var error = $"Message can not be found subscriber. {receivedMessage} \r\n see: https://github.com/dotnetcore/CAP/issues/63"; diff --git a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs index c3497c232..5d7046f56 100644 --- a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs @@ -45,9 +45,9 @@ public static void MessagePublishException(this ILogger logger, long messageId, logger.LogError(ex, $"An exception occured while publishing a message, reason:{reason}. message id:{messageId}"); } - public static void ConsumerExecuted(this ILogger logger, double seconds) + public static void ConsumerExecuted(this ILogger logger, double milliseconds) { - logger.LogDebug($"Consumer executed. Took: {seconds} secs."); + logger.LogDebug($"Consumer executed. Took: {milliseconds} ms."); } public static void ServerStarting(this ILogger logger) diff --git a/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs b/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs index 8ff25c78b..f1ca395f2 100644 --- a/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs +++ b/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs @@ -44,14 +44,14 @@ public ConcurrentDictionary> G } /// - /// Attempts to get the topic exector associated with the specified topic name and group name from the + /// Attempts to get the topic executor associated with the specified topic name and group name from the /// . /// /// The topic name of the value to get. /// The group name of the value to get. - /// topic exector of the value. + /// topic executor of the value. /// true if the key was found, otherwise false. - public bool TryGetTopicExector(string topicName, string groupName, + public bool TryGetTopicExecutor(string topicName, string groupName, out ConsumerExecutorDescriptor matchTopic) { if (Entries == null)