From d942ec249a9b90034b05081e4744f10b5dedbab7 Mon Sep 17 00:00:00 2001 From: BEagle1984 Date: Sat, 21 Dec 2019 10:05:34 +0100 Subject: [PATCH] ISorted and SortBySortIndex --- Directory.Build.props | 2 +- docs/_docs/0-introduction/003-releases.md | 6 ++- docs/_docs/1-quickstart/107-behaviors.md | 14 +++-- .../ISortedBehavior.cs => ISorted.cs} | 4 +- .../Messaging/Publishing/Publisher.cs | 19 +------ ...ions.cs => EnumerableForEachExtensions.cs} | 0 .../Util/EnumerableSortExtensions.cs | 23 ++++++++ .../Behaviors/KafkaPartitioningKeyBehavior.cs | 2 +- .../Behaviors/OutboundProducingBehavior.cs | 2 +- .../Behaviors/OutboundRoutingBehavior.cs | 2 +- .../TestTypes/Behaviors/TestSortedBehavior.cs | 2 +- ...cs => EnumerableForEachExtensionsTests.cs} | 2 +- .../Util/EnumerableSortExtensionsTests.cs | 53 +++++++++++++++++++ 13 files changed, 101 insertions(+), 30 deletions(-) rename src/Silverback.Core/{Messaging/Publishing/ISortedBehavior.cs => ISorted.cs} (64%) rename src/Silverback.Core/Util/{ForEachEnumerableExtensions.cs => EnumerableForEachExtensions.cs} (100%) create mode 100644 src/Silverback.Core/Util/EnumerableSortExtensions.cs rename tests/Silverback.Core.Tests/Util/{EnumerableExtensionsTests.cs => EnumerableForEachExtensionsTests.cs} (94%) create mode 100644 tests/Silverback.Core.Tests/Util/EnumerableSortExtensionsTests.cs diff --git a/Directory.Build.props b/Directory.Build.props index 9b3640842..b29d24a3f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ Silverback is a simple framework to build reactive, event-driven, microservices. MIT Copyright (c) 2019 Sergio Aquilini - -rc2 + -rc3 1.1.0$(VersionSuffix) https://beagle1984.github.io/silverback/ https://github.com/BEagle1984/silverback/ diff --git a/docs/_docs/0-introduction/003-releases.md b/docs/_docs/0-introduction/003-releases.md index a2e1d15fa..c13ad882d 100644 --- a/docs/_docs/0-introduction/003-releases.md +++ b/docs/_docs/0-introduction/003-releases.md @@ -4,11 +4,15 @@ permalink: /docs/releases toc: true --- -## [1.1.0-rc2](https://github.com/BEagle1984/silverback/releases/tag/1.1.0-rc2) +## [1.1.0-rc3](https://github.com/BEagle1984/silverback/releases/tag/1.1.0-rc3) ### What's new * Added `IEndpointsConfigurator` interface to allow splitting the endpoints configuration across multiple types (see [Connecting to a Message Broker]({{ site.baseurl }}/docs/quickstart/message-broker#using-iendpointsconfigurator)) * Added support for distributed tracing (based on standard [System.Diagnostics.DiagnosticSource](https://www.nuget.org/packages/System.Diagnostics.DiagnosticSource/)) +* Added `IProducerBehavior` and `IConsumerBehavior` to create an extension point closer to the actual message broker logic (see [Behaviors]({{ site.baseurl }}/docs/quickstart/behaviors)) + +### Breaking Changes +* `ISortedBehavior` was removed and replaced by a generic `ISorted` interface ## [1.0.5](https://github.com/BEagle1984/silverback/releases/tag/1.0.5) diff --git a/docs/_docs/1-quickstart/107-behaviors.md b/docs/_docs/1-quickstart/107-behaviors.md index 6320a6ced..25261a14f 100644 --- a/docs/_docs/1-quickstart/107-behaviors.md +++ b/docs/_docs/1-quickstart/107-behaviors.md @@ -4,12 +4,14 @@ permalink: /docs/quickstart/behaviors toc: false --- -Behaviors can be used to build a custom pipeline (similar to the asp.net pipeline), easily adding your cross-cutting functionalities such as logging, validation, etc. +The behaviors can be used to build a custom pipeline (similar to the asp.net pipeline), easily adding your cross-cutting functionalities such as logging, validation, etc. + +## IBehavior A behavior must implement the `IBehavior` interface and be registered for dependency injection. ```c# -using Silverback.Messaging.Subscribers; +using Silverback.Messaging.Publishing; public class ValidationBehavior : IBehavior { @@ -43,7 +45,7 @@ public void ConfigureServices(IServiceCollection services) At every call to `IPublisher.Publish` the `Handle` method of each registered behavior is called, passing in the array of messages and the delegate to the next step in the pipeline. This gives you the flexibility to execute any sort of code before and after the messages have been actually published (before or after calling the `next()` step). You can for example modify the messages before publishing them, validate them (like in the above example), add some logging / tracing, etc. -## Message headers +### Example: Message headers The behaviors can be quite useful to get and set the message headers for inbound/outbound messages. @@ -99,4 +101,8 @@ public class LogHeadersBehavior : IBehavior ``` **Note:** `IInboundMessage` and `IOutboundMessage` are internally used by Silverback to wrap the messages being sent to or received from the message broker. -{: .notice--info} \ No newline at end of file +{: .notice--info} + +## IProducerBehavior and IConsumerBehavior + +The `IProducerBehavior` and `IConsumerBehavior` are similar to the `IBehavior` but work at a lower level, much closer to the message broker. You should be able to accomplish most tasks with the normal `IBehavior`. \ No newline at end of file diff --git a/src/Silverback.Core/Messaging/Publishing/ISortedBehavior.cs b/src/Silverback.Core/ISorted.cs similarity index 64% rename from src/Silverback.Core/Messaging/Publishing/ISortedBehavior.cs rename to src/Silverback.Core/ISorted.cs index 133155ded..771c1e127 100644 --- a/src/Silverback.Core/Messaging/Publishing/ISortedBehavior.cs +++ b/src/Silverback.Core/ISorted.cs @@ -1,9 +1,9 @@ // Copyright (c) 2019 Sergio Aquilini // This code is licensed under MIT license (see LICENSE file for details) -namespace Silverback.Messaging.Publishing +namespace Silverback { - public interface ISortedBehavior : IBehavior + public interface ISorted { int SortIndex { get; } } diff --git a/src/Silverback.Core/Messaging/Publishing/Publisher.cs b/src/Silverback.Core/Messaging/Publishing/Publisher.cs index c91683bbb..3d769fa3a 100644 --- a/src/Silverback.Core/Messaging/Publishing/Publisher.cs +++ b/src/Silverback.Core/Messaging/Publishing/Publisher.cs @@ -102,23 +102,8 @@ private Task> InvokeNonExclusiveMethods(IEnumerable .ParallelSelectManyAsync(method => GetMethodInvoker().Invoke(method, messages, executeAsync)); - private IEnumerable GetBehaviors() - { - if (_behaviors == null) - { - var behaviors = _serviceProvider.GetServices(); - var sortedBehaviors = behaviors.OfType().OrderBy(b => b.SortIndex).ToList(); - behaviors = behaviors.Where(b => !(b is ISortedBehavior)).ToList(); - - _behaviors = - sortedBehaviors.Where(b => b.SortIndex <= 0) - .Union(behaviors) - .Union(sortedBehaviors.Where(b => b.SortIndex > 0)) - .ToList(); - } - - return _behaviors; - } + private IEnumerable GetBehaviors() => + _behaviors ??= _serviceProvider.GetServices().SortBySortIndex(); private SubscribedMethodInvoker GetMethodInvoker() => _methodInvoker ??= _serviceProvider.GetRequiredService(); diff --git a/src/Silverback.Core/Util/ForEachEnumerableExtensions.cs b/src/Silverback.Core/Util/EnumerableForEachExtensions.cs similarity index 100% rename from src/Silverback.Core/Util/ForEachEnumerableExtensions.cs rename to src/Silverback.Core/Util/EnumerableForEachExtensions.cs diff --git a/src/Silverback.Core/Util/EnumerableSortExtensions.cs b/src/Silverback.Core/Util/EnumerableSortExtensions.cs new file mode 100644 index 000000000..855d364aa --- /dev/null +++ b/src/Silverback.Core/Util/EnumerableSortExtensions.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2019 Sergio Aquilini +// This code is licensed under MIT license (see LICENSE file for details) + +using System.Collections.Generic; +using System.Linq; + +namespace Silverback.Util +{ + internal static class EnumerableSortExtensions + { + public static IEnumerable SortBySortIndex(this IEnumerable items) + { + var sorted = items.OfType().OrderBy(b => b.SortIndex).ToList(); + var unsortable = items.Where(b => !(b is ISorted)).ToList(); + + return sorted + .Where(b => b.SortIndex <= 0).Cast() + .Union(unsortable) + .Union(sorted.Where(b => b.SortIndex > 0).Cast()) + .ToList(); + } + } +} \ No newline at end of file diff --git a/src/Silverback.Integration.Kafka/Messaging/Behaviors/KafkaPartitioningKeyBehavior.cs b/src/Silverback.Integration.Kafka/Messaging/Behaviors/KafkaPartitioningKeyBehavior.cs index cb7a960bd..f50ef816d 100644 --- a/src/Silverback.Integration.Kafka/Messaging/Behaviors/KafkaPartitioningKeyBehavior.cs +++ b/src/Silverback.Integration.Kafka/Messaging/Behaviors/KafkaPartitioningKeyBehavior.cs @@ -12,7 +12,7 @@ namespace Silverback.Messaging.Behaviors { - public class KafkaPartitioningKeyBehavior : ISortedBehavior + public class KafkaPartitioningKeyBehavior : IBehavior, ISorted { public int SortIndex { get; } = 200; diff --git a/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundProducingBehavior.cs b/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundProducingBehavior.cs index b9202a365..6a5055aa7 100644 --- a/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundProducingBehavior.cs +++ b/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundProducingBehavior.cs @@ -12,7 +12,7 @@ namespace Silverback.Messaging.Connectors.Behaviors { - public class OutboundProducingBehavior : ISortedBehavior + public class OutboundProducingBehavior : IBehavior, ISorted { private readonly IEnumerable _outboundConnectors; diff --git a/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRoutingBehavior.cs b/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRoutingBehavior.cs index 5e7cff7af..b1f2ac743 100644 --- a/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRoutingBehavior.cs +++ b/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRoutingBehavior.cs @@ -13,7 +13,7 @@ namespace Silverback.Messaging.Connectors.Behaviors { - public class OutboundRoutingBehavior : ISortedBehavior + public class OutboundRoutingBehavior : IBehavior, ISorted { private readonly IServiceProvider _serviceProvider; private readonly IOutboundRoutingConfiguration _routing; diff --git a/tests/Silverback.Core.Tests/TestTypes/Behaviors/TestSortedBehavior.cs b/tests/Silverback.Core.Tests/TestTypes/Behaviors/TestSortedBehavior.cs index 777761360..68e20b157 100644 --- a/tests/Silverback.Core.Tests/TestTypes/Behaviors/TestSortedBehavior.cs +++ b/tests/Silverback.Core.Tests/TestTypes/Behaviors/TestSortedBehavior.cs @@ -7,7 +7,7 @@ namespace Silverback.Tests.Core.TestTypes.Behaviors { - public class TestSortedBehavior : ISortedBehavior + public class TestSortedBehavior : IBehavior, ISorted { private readonly List _calls; diff --git a/tests/Silverback.Core.Tests/Util/EnumerableExtensionsTests.cs b/tests/Silverback.Core.Tests/Util/EnumerableForEachExtensionsTests.cs similarity index 94% rename from tests/Silverback.Core.Tests/Util/EnumerableExtensionsTests.cs rename to tests/Silverback.Core.Tests/Util/EnumerableForEachExtensionsTests.cs index b1059070c..23aa75a29 100644 --- a/tests/Silverback.Core.Tests/Util/EnumerableExtensionsTests.cs +++ b/tests/Silverback.Core.Tests/Util/EnumerableForEachExtensionsTests.cs @@ -9,7 +9,7 @@ namespace Silverback.Tests.Core.Util { - public class EnumerableForEachExtensions + public class EnumerableForEachExtensionsTests { [Fact] public void ForEachTest() diff --git a/tests/Silverback.Core.Tests/Util/EnumerableSortExtensionsTests.cs b/tests/Silverback.Core.Tests/Util/EnumerableSortExtensionsTests.cs new file mode 100644 index 000000000..f640ae584 --- /dev/null +++ b/tests/Silverback.Core.Tests/Util/EnumerableSortExtensionsTests.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Sergio Aquilini +// This code is licensed under MIT license (see LICENSE file for details) + +using System.Collections.Generic; +using FluentAssertions; +using Silverback.Messaging.Publishing; +using Silverback.Tests.Core.TestTypes.Behaviors; +using Silverback.Tests.Core.TestTypes.Messages; +using Silverback.Util; +using Xunit; + +namespace Silverback.Tests.Core.Util +{ + public class EnumerableSortExtensionsTests + { + [Fact] + public void SortBySortIndex_SomeItems_SortedAsExpected() + { + var items = new[] + { + new SortedItem(100), + new SortedItem(-50), + new SortedItem(50), + new SortedItem(-100), + new Item("unsorted3"), + new Item("unsorted2") + }; + + var sorted = items.SortBySortIndex(); + + sorted.Should().BeEquivalentTo( + new SortedItem(-100), + new SortedItem(-50), + new Item("unsorted3"), + new Item("unsorted2"), + new SortedItem(50), + new SortedItem(100) + ); + } + + private class Item + { + public Item(string id) => Id = id; + public string Id { get; } + } + + private class SortedItem : Item, ISorted + { + public SortedItem(int sortIndex) : base(sortIndex.ToString()) => SortIndex = sortIndex; + public int SortIndex { get;} + } + } +} \ No newline at end of file