From 786ed8f73d25c902b01f6232ba520e1c9e75cf7b Mon Sep 17 00:00:00 2001 From: savorboard Date: Thu, 14 Dec 2023 21:55:50 +0800 Subject: [PATCH] Update docs & code cleanup. --- docs/content/about/release-notes.md | 163 ++++++++++++++++++ .../Controllers/ValuesController.cs | 17 +- .../ICapTransaction.MongoDB.cs | 2 + .../ICapTransaction.SqlServer.cs | 1 + src/DotNetCore.CAP/CAP.Builder.cs | 4 +- src/DotNetCore.CAP/CAP.Options.cs | 2 +- .../CAP.ServiceCollectionExtensions.cs | 2 +- src/DotNetCore.CAP/ICapTransaction.Base.cs | 4 + .../Internal/ICapPublisher.Default.cs | 6 +- .../IConsumerServiceSelector.Default.cs | 6 +- .../Processor/IDispatcher.Default.cs | 8 +- .../Processor/IProcessor.NeedRetry.cs | 2 +- .../ServiceBusProducerBuilderTests.cs | 4 +- .../ServiceBusTransportTests.cs | 2 +- 14 files changed, 193 insertions(+), 30 deletions(-) diff --git a/docs/content/about/release-notes.md b/docs/content/about/release-notes.md index 607bd97d2..802bcc3fd 100644 --- a/docs/content/about/release-notes.md +++ b/docs/content/about/release-notes.md @@ -5,6 +5,169 @@ hide: # Release Notes +## Version 8.0.0 (Dec 14, 2023) + +**Breaking Changes** + +Removed `DefaultAuthenticationScheme`, `UseChallengeOnAuth`, `DefaultChallengeScheme` and `AuthorizationPolicy` options of DotNetCore.CAP.Dashboard. +Now CAP dashboard auth/authz mechanism to leverage the "ASP.NET Core" way of doing it, see #1428. + +* Streamlined auth via asp.net middlewares. (#1434) Thanks @mviegas + +**Features:** + +* Fully Support .NET 8. +* Add `FallbackWindowLookbackSeconds` option to configure the retry processor to pick up the backtrack time window for Scheduled or Failed status messages. (#1455) Thanks @apatozi +* Update IConsumerRegister.Default.cs to make dispose thread safe. (#1438) Thanks @blashbul +* Compatible with .NET 8's dependency injection KeyedService. (#1436) Thanks @EashShow +* Add virtual method to custom delay backtrack time window during delayed publishing large messges. (#1429) Thanks @PoteRii + +**Bug Fixed:** + +* Fixed message infinite retry of messages after subscriber is removed. (#1456) Thanks @bschwehn +* Fixed open telemetry context lost on consumer retry and Baggage Propagation. (#1452) Thanks @bschwehn +* Fixed NATS do not handle reconnect if the nats server is forcibly shutdown and then restarted. (#1449) Thanks @davidterins +* Fixed outbox pattern messages does not recovery when using DotNetCore.CAP.InMemoryStorage. (#1439) Thanks @davidterins +* Fixed open telemetry subscriber thows null reference when using azure service bus without connection string. (#1432) Thanks @demorgi +* Fixed double registration of event handler for azure service bus. (#1427) Thanks @demorgi +* Fixed publish delay message not working in sql server transaction. (#1422) Thanks @xiangxiren + +## Version 7.2.2 (Nov 1, 2023) + +**Features:** + +* NATS support consumer config DeliverPolicy, default to New. (#1404) +* Be able to configure if to subscribe to custom producer topic. (#1409) @demorgi + +**Bug Fixed:** + +* Try to fixes RabbitMQ basicConsume TimeOutException. (#1405) @yang-xiaodong +* Change MongoDb index from descending to ascending. (#1415) Thanks @ustaserdar +* Fixed parent span for "Event Persistence" activity trace. (#1407) Thanks @blashbul +* Fixed OpenTelemetry Dynatrace IsRemote flag. (#1402) Thanks @phmonte +* Mark Mongo time serialized to local instance time by default. (#1400) +* Fixed k8s dashboard meta query error in standalone mode. @yang-xiaodong +* Azure Service Bus, consumer fails if subscription has session enabled. (#1396, #1397) Thanks @demorgi + +## Version 7.2.1 (Sep 8, 2023) + +**Features:** + +* The options `EnableConsumerPrefetch` and `UseDispatchingPerGroup` will work together without interference. (#1399) + +**Bug Fixed:** + +* Fixed SqlServer sql case sensitive in dashboard query. (#1389) +* Fixed Redis endpoint is null in DotNetCore.CAP.OpenTelemetry. (#1384) + + +## Version 7.2.0 (Jul 30, 2023) + +**Breaking Changes** + +* Remove `ProducerThreadCount` configuration option. Now automatically send task managed by the .NET thread pool. (#1380) +* Change the SnowflakeId from static singleton to dependency injection singleton. (#1322) + +**Features:** + +* Add support for kubernetes discovery in dashboard. (#1362) +* Message send task and consumer execute task managed by .net thread pool. (#1380) +* Upgrade dependencies of NuGet packages. + +**Bug Fixed:** + +* Fixed BasicQosOptions not working as expected for RabbitMQ transport. (#1318) +* Revert BeginTransactionAsync support. (#1376) +* Fixed SqlServer transaction rollback message still sent out. (#1378) +* +## Version 7.1.4 (Jun 17, 2023) + +**Features:** + +* Add suppport `AutoDeleteOnIdle` option for Azure Service Bus. (#1350) Thanks @StevenDevooght + +**Bug Fixed:** + +* Keep the originall stack when consumer exception occurs. (#1341) Thanks @tomyangOK +* Fixed multiple invocations caused when the retry processor exceeded the `FailedRetryInterval`. (#1359) Thanks @li-zheng-hao +* Fixed thread blocking when enable `UseDispatchingPerGroup` option. (#1356) Thanks @sampsonye @li-zheng-hao +* +## Version 7.1.3 (May 17, 2023) + +**Features:** + +* Allow Explicit to set AllowAnonymous for the dashboard API. (#1335) +* Update dashboard UI style +* Add Cancellation token for BeginTransactionAsync. (#1317) Thanks @denis-tsv + +**Bug Fixed:** + +* Fixed postgresql AcquireLockAsync sql error. (#1320) Thanks @guochen2 +* Fixed redis transport order pool connections non-lazy created connections. (#1332) Thanks @MahmoudSamir101 +* Fixed mysql 8.0 storage skip locked not available bug. (#1330) Thanks @yang-xiaodong + +## Version 7.1.2 (Apr 25, 2023) + +**Bug Fixed:** + +* Optimizing consumer duplicate detection warning logs. (#1314) +* Fixes NATS consumption repeat when multiple consumer threads. +* Fixes NATS transport infinity reconnect race condition. (#1311) + +## Version 7.1.1 (Apr 7, 2023) + +**Features:** + +* Add support topic config for kafka. (#1303) +* Log in to dashboard with JWT authentication. (#1306) + +**Bug Fixed:** + +* Fixed sqlserver character string convert to datetime2 exception. (#1302) +* Fixed dashboard consul node proxy switch bug. (#1307) + +## Version 7.1.0 (Mar 5, 2023) + +**Features:** + +* Add option to support distributed locks for retry processor. (#1272) Thanks @li-zheng-hao +* Add option to support set BasicQos for RabbitMQ. (#1267) Thanks @nunorelvao +* Add option to set queue type for RabbitMQ. (#1281) Thanks @PaulCousinsTTEducation +* Add support publish to mutiple topics for Azure Service Bus. (#1283) Thanks @jonekdahl @mviegas + +**Bug Fixed:** + +* Fixed dashboard re-execute message throw null exception for MongoDB. (#1279) Thanks @cagataykiziltan + +## Version 7.0.3 (Feb 2, 2023) + +**Features:** + +* Add SQL Filters option on topic subscribtion for AzureServiceBus. (#1263) Thanks @giorgilekveishvili-meama +* Add EF BeginTransaction extensions overload with isolationlevel and async version. (#1266) @xshaheen + +**Bug Fixed:** + +* Fixed dashboard re-execute message throw null exception for SqlServer and Postgres. (#1259) Thanks @coolyuwk + +## Version 7.0.2 (Jan 9, 2023) + +**Features:** + +* Change AzureServiceBus nuget package from Microsoft.Azure.ServiceBus to Azure.Messaging.ServiceBus. (https://github.com/dotnetcore/CAP/pull/1253) + +**Bug Fixed:** + +* Fixed redis streams json serialize exception. (#1254) +* Fixed dashboard route in balzor server app. (not support wasm) (#1244) + +## Version 7.0.1 (2022-12-16) + +**Bug Fixed:** + +* Fixed dashboard not working in balzor app. (#1244) +* Fixed error when published Winform with 'Produce Single File'. (#1245) + ## Version 7.0.0 (2022-11-27) **Breaking Changes:** diff --git a/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs b/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs index e9fd20416..51137b5de 100644 --- a/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs @@ -9,15 +9,8 @@ namespace Sample.Kafka.PostgreSql.Controllers { [Route("api/[controller]")] - public class ValuesController : Controller, ICapSubscribe + public class ValuesController(ICapPublisher producer) : Controller, ICapSubscribe { - private readonly ICapPublisher _capBus; - - public ValuesController(ICapPublisher producer) - { - _capBus = producer; - } - [Route("~/control/start")] public async Task Start([FromServices] IBootstrapper bootstrapper) { @@ -36,7 +29,7 @@ public async Task Stop([FromServices] IBootstrapper bootstrapper) [Route("~/delay/{delaySeconds:int}")] public async Task Delay(int delaySeconds) { - await _capBus.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), "sample.kafka.postgrsql", DateTime.Now); + await producer.PublishDelayAsync(TimeSpan.FromSeconds(delaySeconds), "sample.kafka.postgrsql", DateTime.Now); return Ok(); } @@ -45,7 +38,7 @@ public async Task Delay(int delaySeconds) [Route("~/without/transaction")] public async Task WithoutTransaction() { - await _capBus.PublishAsync("sample.kafka.postgrsql", DateTime.Now); + await producer.PublishAsync("sample.kafka.postgrsql", DateTime.Now); return Ok(); } @@ -55,12 +48,12 @@ public IActionResult AdonetWithTransaction() { using (var connection = new NpgsqlConnection("")) { - using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false)) + using (var transaction = connection.BeginTransaction(producer, autoCommit: false)) { //your business code connection.Execute("insert into test(name) values('test')", transaction: (IDbTransaction)transaction.DbTransaction); - _capBus.Publish("sample.kafka.postgrsql", DateTime.Now); + producer.Publish("sample.kafka.postgrsql", DateTime.Now); transaction.Commit(); } diff --git a/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs index 07e5df243..18bc36cc1 100644 --- a/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.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; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -56,6 +57,7 @@ public override void Dispose() { (DbTransaction as IClientSessionHandle)?.Dispose(); DbTransaction = null; + GC.SuppressFinalize(this); } } diff --git a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs index 347491963..8f1a08a43 100644 --- a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs @@ -131,6 +131,7 @@ public override void Dispose() } DbTransaction = null; + GC.SuppressFinalize(this); } } diff --git a/src/DotNetCore.CAP/CAP.Builder.cs b/src/DotNetCore.CAP/CAP.Builder.cs index 14a6ec1c0..31e6f9777 100644 --- a/src/DotNetCore.CAP/CAP.Builder.cs +++ b/src/DotNetCore.CAP/CAP.Builder.cs @@ -111,7 +111,7 @@ public CapBuilder AddSubscribeFilter() where T : class, ISubscribeFilter /// Assemblies to scan subscriber public CapBuilder AddSubscriberAssembly(params Assembly[] assemblies) { - if (assemblies == null) throw new ArgumentNullException(nameof(assemblies)); + ArgumentNullException.ThrowIfNull(assemblies); Services.Replace(new ServiceDescriptor(typeof(IConsumerServiceSelector), x => new AssemblyConsumerServiceSelector(x, assemblies), @@ -126,7 +126,7 @@ public CapBuilder AddSubscriberAssembly(params Assembly[] assemblies) /// public CapBuilder AddSubscriberAssembly(params Type[] handlerAssemblyMarkerTypes) { - if (handlerAssemblyMarkerTypes == null) throw new ArgumentNullException(nameof(handlerAssemblyMarkerTypes)); + ArgumentNullException.ThrowIfNull(handlerAssemblyMarkerTypes); AddSubscriberAssembly(handlerAssemblyMarkerTypes.Select(t => t.GetTypeInfo().Assembly).ToArray()); diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index 2edc32edd..1178ba087 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -131,7 +131,7 @@ public CapOptions() /// public void RegisterExtension(ICapOptionsExtension extension) { - if (extension == null) throw new ArgumentNullException(nameof(extension)); + ArgumentNullException.ThrowIfNull(extension); Extensions.Add(extension); } diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 9a22b997a..6f425c99b 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -25,7 +25,7 @@ public static class ServiceCollectionExtensions /// An for application services. public static CapBuilder AddCap(this IServiceCollection services, Action setupAction) { - if (setupAction == null) throw new ArgumentNullException(nameof(setupAction)); + ArgumentNullException.ThrowIfNull(setupAction); services.AddSingleton(_ => services); services.TryAddSingleton(new CapMarkerService("CAP")); diff --git a/src/DotNetCore.CAP/ICapTransaction.Base.cs b/src/DotNetCore.CAP/ICapTransaction.Base.cs index 9a4b729f5..f13af004f 100644 --- a/src/DotNetCore.CAP/ICapTransaction.Base.cs +++ b/src/DotNetCore.CAP/ICapTransaction.Base.cs @@ -45,17 +45,21 @@ protected virtual void Flush() { while (!_bufferList.IsEmpty) { +#pragma warning disable CA2012 // Use ValueTasks correctly if (_bufferList.TryDequeue(out var message)) { var isDelayMessage = message.Origin.Headers.ContainsKey(Headers.DelayTime); if (isDelayMessage) { + _dispatcher.EnqueueToScheduler(message, DateTime.Parse(message.Origin.Headers[Headers.SentTime]!)).ConfigureAwait(false); + } else { _dispatcher.EnqueueToPublish(message).ConfigureAwait(false); } +#pragma warning restore CA2012 // Use ValueTasks correctly } } } diff --git a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs index 078d52d82..ad87ce9be 100644 --- a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs +++ b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs @@ -185,7 +185,7 @@ private async Task PublishInternalAsync(string name, T? value, IDictionary(string name, T? value, IDictionary executeDescriptor) { - if (key == null) throw new ArgumentNullException(nameof(key)); + ArgumentNullException.ThrowIfNull(key); return executeDescriptor.FirstOrDefault(x => x.TopicName.Equals(key, StringComparison.InvariantCultureIgnoreCase)); @@ -208,7 +208,7 @@ private ConsumerExecutorDescriptor InitDescriptor( private ConsumerExecutorDescriptor? MatchWildcardUsingRegex(string key, IReadOnlyList executeDescriptor) { - var group = executeDescriptor.First().Attribute.Group; + var group = executeDescriptor[0].Attribute.Group; if (!_cacheList.TryGetValue(group, out var tmpList)) { tmpList = executeDescriptor.Select(x => new RegexExecuteDescriptor diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index 8f62417f1..47bce901e 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -190,13 +190,14 @@ public async ValueTask EnqueueToExecute(MediumMessage message, ConsumerExecutorD } catch (Exception e) { - _logger.LogError(e, $"An exception occurred when invoke subscriber. MessageId:{message.DbId}"); + _logger.LogError(e, "An exception occurred when invoke subscriber. MessageId:{MessageId}", message.DbId); } } public void Dispose() { _tasksCts?.Dispose(); + GC.SuppressFinalize(this); } private async ValueTask Sending() @@ -217,8 +218,7 @@ private async ValueTask Sending() } catch (Exception ex) { - _logger.LogError(ex, - $"An exception occurred when sending a message to the transport. Id:{message.DbId}"); + _logger.LogError(ex, "An exception occurred when sending a message to the transport. Id:{MessageId}", message.DbId); } } catch (OperationCanceledException) @@ -245,7 +245,7 @@ private async ValueTask Processing() } catch (Exception e) { - _logger.LogError(e, $"An exception occurred when invoke subscriber. MessageId:{message.Item1.DbId}"); + _logger.LogError(e, "An exception occurred when invoking subscriber. MessageId:{MessageId}", message.Item1.DbId); } } catch (OperationCanceledException) diff --git a/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs b/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs index d2ebf5520..63141d218 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs @@ -45,7 +45,7 @@ public MessageNeedToRetryProcessor(IOptions options, ILogger(); diff --git a/test/DotNetCore.CAP.AzureServiceBus.Test/Producer/ServiceBusProducerBuilderTests.cs b/test/DotNetCore.CAP.AzureServiceBus.Test/Producer/ServiceBusProducerBuilderTests.cs index bf82d257b..825502eba 100644 --- a/test/DotNetCore.CAP.AzureServiceBus.Test/Producer/ServiceBusProducerBuilderTests.cs +++ b/test/DotNetCore.CAP.AzureServiceBus.Test/Producer/ServiceBusProducerBuilderTests.cs @@ -2,7 +2,7 @@ using Shouldly; using Xunit; -namespace DotNetCore.CAP.AzureServiceBus.Tests.Producer; +namespace DotNetCore.CAP.AzureServiceBus.Test.Producer; public record MessagePublished; @@ -12,7 +12,7 @@ public class ServiceBusProducerBuilderTests public void Should_HavePropertiesCorrectlySet_When_Obsolete_BuildMethodIsExecuted() { var producer = new ServiceBusProducerDescriptorBuilder() - .WithTopic("my-destination") + .UseTopic("my-destination") .Build(); producer.ShouldNotBeNull(); diff --git a/test/DotNetCore.CAP.AzureServiceBus.Test/ServiceBusTransportTests.cs b/test/DotNetCore.CAP.AzureServiceBus.Test/ServiceBusTransportTests.cs index a461e2874..c2b788657 100644 --- a/test/DotNetCore.CAP.AzureServiceBus.Test/ServiceBusTransportTests.cs +++ b/test/DotNetCore.CAP.AzureServiceBus.Test/ServiceBusTransportTests.cs @@ -9,7 +9,7 @@ using Shouldly; using Xunit; -namespace DotNetCore.CAP.AzureServiceBus.Tests; +namespace DotNetCore.CAP.AzureServiceBus.Test; public class ServiceBusTransportTests {