From 71a6db18f12df1ba0c31df7ec7902af65a2d8b11 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Tue, 26 Feb 2019 14:43:30 -0800 Subject: [PATCH 01/11] Added BrokerClient to replace Helpers. Added cacheing of BrokerService Uri so we don't have to look it up over and over. --- README.md | 63 +----- ...GivenSubscriberStatefulServiceBaseTests.cs | 87 +------- ...ivenSubscriberStatelessServiceBaseTests.cs | 87 +------- .../MockBrokerServiceLocator.cs | 81 ++++++++ .../BrokerServiceBase.cs | 28 ++- .../Helpers/BrokerClient.cs | 189 ++++++++++++++++++ .../Helpers/BrokerServiceLocator.cs | 37 +++- .../Helpers/IBrokerClient.cs | 81 ++++++++ .../Helpers/IBrokerServiceLocator.cs | 4 +- .../Helpers/SubscriberExtensions.cs | 50 +++++ .../Helpers/SubscriberServiceHelper.cs | 29 +-- ServiceFabric.PubSubActors/IBrokerService.cs | 16 ++ .../SubscriberStatefulServiceBase.cs | 50 +++-- .../SubscriberStatelessServiceBase.cs | 47 +++-- 14 files changed, 557 insertions(+), 292 deletions(-) create mode 100644 ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs create mode 100644 ServiceFabric.PubSubActors/Helpers/BrokerClient.cs create mode 100644 ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs create mode 100644 ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs diff --git a/README.md b/README.md index 8f76d10..d0e6a16 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,12 @@ public class PublishedMessageTwo } ``` +### Publishing messages from Service or Actor +```csharp +var brokerClient = new BrokerClient(); +brokerClient.PublishMessageAsync(new PublishedMessageOne { Content = "Hello PubSub World, from Subscriber, using Broker Service!" }) +``` + ### Subscribing to messages using Actors *Create a sample Actor that implements 'ISubscriberActor', to become a subscriber to messages.* In this example, the Actor called 'SubscribingActor' subscribes to messages of Type 'PublishedMessageOne'. @@ -169,7 +175,7 @@ Now open the file SubscribingStatelessService.cs in the project 'SubscribingStat ```csharp internal sealed class SubscribingStatelessService : SubscriberStatelessServiceBase { - public SubscribingStatelessService(StatelessServiceContext serviceContext, ISubscriberServiceHelper subscriberServiceHelper = null) : base(serviceContext, subscriberServiceHelper) + public SubscribingStatelessService(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext, subscriberServiceHelper) { } @@ -246,64 +252,11 @@ For stateful services, use the `StatefulSubscriberServiceBootstrapper`. *Check the Demo project for a working reference implementation.* -### Publishing messages from Actors -*Create a sample Actor that publishes messages.* -In this example, the Actor called 'PublishingActor' publishes messages of Type 'PublishedMessageOne'. - -In this example, the Publisher Actor publishes messages of Type 'PublishedMessageOne'. -Add a Reliable Stateless Actor project called 'PublishingActor'. -Add Nuget package 'ServiceFabric.PubSubActors' to 'PublishingActor'. -Add Nuget package 'ServiceFabric.PubSubActors.Interfaces' to 'PublishingActor.Interfaces'. -Add a project reference to the shared data contracts library ('DataContracts'). - -Go to the project 'PublishingActor.Interfaces' and open the file IPublishingActor.cs. -Replace the contents with the code below, to allow external callers to trigger a publish action (not required, Actors can decide for themselves too): - -```csharp -public interface IPublishingActor : IActor -{ - //enables external callers to trigger a publish action, not required for functionality - Task PublishMessageOneAsync(); - Task PublishMessageTwoAsync(); -} -``` - -Now open the file PublishingActor.cs in the project 'PublishingActor' and replace the contents with this code: - -https://github.com/loekd/ServiceFabric.PubSubActors/blob/master/ServiceFabric.PubSubActors.Demo/PublishingActor/PublishingActor.cs - -### Publishing messages from Services -*Create a sample Service that publishes messages.* -In this example, the Service called 'PublishingStatelessService' publishes messages of Type 'PublishedMessageOne'. - -Add a Reliable Stateless Service project called 'PublishingStatelessService'. -Add Nuget package 'ServiceFabric.PubSubActors' to 'PublishingStatelessService'. -Add Nuget package 'ServiceFabric.PubSubActors.Interfaces' to 'PublishingStatelessService'. -Add a project reference to the shared data contracts library ('DataContracts'). - -Go to the project 'DataContracts' and add an interface file IPublishingStatelessService.cs. -Add the code below: -```csharp -[ServiceContract] -public interface IPublishingStatelessService : IService -{ - //allows external callers to trigger a publish action, not required for functionality - [OperationContract] - Task PublishMessageOneAsync(); - [OperationContract] - Task PublishMessageTwoAsync(); -} -``` -Open the file 'PublishingStatelessService.cs'. Replace the contents with the code below: - -https://github.com/loekd/ServiceFabric.PubSubActors/blob/master/ServiceFabric.PubSubActors.Demo/PublishingStatelessService/PublishingStatelessService.cs - - ## Routing **This experimental feature works only when using the `DefaultPayloadSerializer`.** It adds support for an additional subscriber filter, based on message content. -### Example +### Example Given this message type: diff --git a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs index 0b3b25b..4c79bca 100644 --- a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs +++ b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; using System.Fabric; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.ServiceFabric.Services.Runtime; using Microsoft.VisualStudio.TestTools.UnitTesting; using ServiceFabric.Mocks; using ServiceFabric.PubSubActors.Helpers; @@ -16,19 +12,14 @@ namespace ServiceFabric.PubSubActors.Tests [TestClass] public class GivenSubscriberStatefulServiceBaseTests { - [TestMethod] - public async Task WhenMarkedServiceScansAttributes_ThenCorrectlyRegistered() - { - var service = new MockSubscriberStatefulServiceBase(MockStatefulServiceContextFactory.Default, new MockSubscriberServiceHelper()); - await service.InvokeOnOpenAsync(ReplicaOpenMode.New, CancellationToken.None); - - Assert.AreEqual(1, service.Handlers.Count()); - } - [TestMethod] public async Task WhenMarkedServiceReceivesMessage_ThenCorrectMethodIsInvoked() { - var service = new MockSubscriberStatefulServiceBase(MockStatefulServiceContextFactory.Default, new MockSubscriberServiceHelper()); + var service = new MockSubscriberStatefulServiceBase(MockStatefulServiceContextFactory.Default, new BrokerClient(new MockBrokerServiceLocator())); + service.SetPartition(new MockStatefulServicePartition + { + PartitionInfo = new SingletonPartitionInformation() + }); await service.InvokeOnOpenAsync(ReplicaOpenMode.New, CancellationToken.None); await service.ReceiveMessageAsync(new MockMessage {SomeValue = "SomeValue"}.CreateMessageWrapper()); Assert.IsTrue(service.MethodCalled); @@ -37,78 +28,22 @@ public async Task WhenMarkedServiceReceivesMessage_ThenCorrectMethodIsInvoked() [TestMethod] public async Task WhenMarkedServiceReceivesMessage_ThenCorrectOverloadMethodIsInvoked() { - var service = new MockSubscriberStatefulServiceBase(MockStatefulServiceContextFactory.Default, new MockSubscriberServiceHelper()); + var service = new MockSubscriberStatefulServiceBase(MockStatefulServiceContextFactory.Default, new BrokerClient(new MockBrokerServiceLocator())); + service.SetPartition(new MockStatefulServicePartition + { + PartitionInfo = new SingletonPartitionInformation() + }); await service.InvokeOnOpenAsync(ReplicaOpenMode.New, CancellationToken.None); await service.ReceiveMessageAsync(new MockMessageSpecialized { SomeValue = "SomeValue" }.CreateMessageWrapper()); Assert.IsTrue(service.MethodCalled); } - public class MockSubscriberServiceHelper : ISubscriberServiceHelper - { - private ISubscriberServiceHelper _helper; - - public MockSubscriberServiceHelper() - { - _helper = new SubscriberServiceHelper(); - } - public Task RegisterMessageTypeAsync(StatelessService service, Type messageType, Uri brokerServiceName = null, - string listenerName = null) - { - return Task.CompletedTask; - } - - public Task UnregisterMessageTypeAsync(StatelessService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null) - { - return Task.CompletedTask; - } - - public Task RegisterMessageTypeAsync(StatefulService service, Type messageType, Uri brokerServiceName = null, - string listenerName = null) - { - return Task.CompletedTask; - } - - public Task UnregisterMessageTypeAsync(StatefulService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null) - { - return Task.CompletedTask; - } - - public Dictionary> DiscoverMessageHandlers(T handlerClass) where T : class - { - return _helper.DiscoverMessageHandlers(handlerClass); - } - - public Task SubscribeAsync(ServiceReference serviceReference, IEnumerable messageTypes, Uri broker = null) - { - return _helper.SubscribeAsync(serviceReference, messageTypes, broker); - } - - public Task ProccessMessageAsync(MessageWrapper messageWrapper, Dictionary> handlers) - { - return _helper.ProccessMessageAsync(messageWrapper, handlers); - } - - public ServiceReference CreateServiceReference(StatelessService service, string listenerName = null) - { - return new ServiceReference(); - } - - public ServiceReference CreateServiceReference(StatefulService service, string listenerName = null) - { - return new ServiceReference(); - } - } - public class MockSubscriberStatefulServiceBase : SubscriberStatefulServiceBase { public bool MethodCalled { get; private set; } - internal new IEnumerable> Handlers => base.Handlers.Values; - /// - public MockSubscriberStatefulServiceBase(StatefulServiceContext serviceContext, ISubscriberServiceHelper subscriberServiceHelper = null) : base(serviceContext, subscriberServiceHelper) + public MockSubscriberStatefulServiceBase(StatefulServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext, brokerClient) { } diff --git a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs index 3ffda12..408462e 100644 --- a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs +++ b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs @@ -1,10 +1,6 @@ -using System; -using System.Collections.Generic; using System.Fabric; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.ServiceFabric.Services.Runtime; using Microsoft.VisualStudio.TestTools.UnitTesting; using ServiceFabric.Mocks; using ServiceFabric.PubSubActors.Helpers; @@ -16,19 +12,14 @@ namespace ServiceFabric.PubSubActors.Tests [TestClass] public class GivenSubscriberStatelessServiceBaseTests { - [TestMethod] - public async Task WhenMarkedServiceScansAttributes_ThenCorrectlyRegistered() - { - var service = new MockSubscriberStatelessServiceBase(MockStatelessServiceContextFactory.Default, new MockSubscriberServiceHelper()); - await service.InvokeOnOpenAsync(CancellationToken.None); - - Assert.AreEqual(1, service.Handlers.Count()); - } - [TestMethod] public async Task WhenMarkedServiceReceivesMessage_ThenCorrectMethodIsInvoked() { - var service = new MockSubscriberStatelessServiceBase(MockStatelessServiceContextFactory.Default, new MockSubscriberServiceHelper()); + var service = new MockSubscriberStatelessServiceBase(MockStatelessServiceContextFactory.Default, new BrokerClient(new MockBrokerServiceLocator())); + service.SetPartition(new MockStatelessServicePartition + { + PartitionInfo = new SingletonPartitionInformation() + }); await service.InvokeOnOpenAsync(CancellationToken.None); await service.ReceiveMessageAsync(new MockMessage {SomeValue = "SomeValue"}.CreateMessageWrapper()); Assert.IsTrue(service.MethodCalled); @@ -37,78 +28,22 @@ public async Task WhenMarkedServiceReceivesMessage_ThenCorrectMethodIsInvoked() [TestMethod] public async Task WhenMarkedServiceReceivesMessage_ThenCorrectOverloadMethodIsInvoked() { - var service = new MockSubscriberStatelessServiceBase(MockStatelessServiceContextFactory.Default, new MockSubscriberServiceHelper()); + var service = new MockSubscriberStatelessServiceBase(MockStatelessServiceContextFactory.Default, new BrokerClient(new MockBrokerServiceLocator())); + service.SetPartition(new MockStatelessServicePartition + { + PartitionInfo = new SingletonPartitionInformation() + }); await service.InvokeOnOpenAsync(CancellationToken.None); await service.ReceiveMessageAsync(new MockMessageSpecialized { SomeValue = "SomeValue" }.CreateMessageWrapper()); Assert.IsTrue(service.MethodCalled); } - public class MockSubscriberServiceHelper : ISubscriberServiceHelper - { - private ISubscriberServiceHelper _helper; - - public MockSubscriberServiceHelper() - { - _helper = new SubscriberServiceHelper(); - } - public Task RegisterMessageTypeAsync(StatelessService service, Type messageType, Uri brokerServiceName = null, - string listenerName = null) - { - return Task.CompletedTask; - } - - public Task UnregisterMessageTypeAsync(StatelessService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null) - { - return Task.CompletedTask; - } - - public Task RegisterMessageTypeAsync(StatefulService service, Type messageType, Uri brokerServiceName = null, - string listenerName = null) - { - return Task.CompletedTask; - } - - public Task UnregisterMessageTypeAsync(StatefulService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null) - { - return Task.CompletedTask; - } - - public Dictionary> DiscoverMessageHandlers(T handlerClass) where T : class - { - return _helper.DiscoverMessageHandlers(handlerClass); - } - - public Task SubscribeAsync(ServiceReference serviceReference, IEnumerable messageTypes, Uri broker = null) - { - return _helper.SubscribeAsync(serviceReference, messageTypes, broker); - } - - public Task ProccessMessageAsync(MessageWrapper messageWrapper, Dictionary> handlers) - { - return _helper.ProccessMessageAsync(messageWrapper, handlers); - } - - public ServiceReference CreateServiceReference(StatelessService service, string listenerName = null) - { - return new ServiceReference(); - } - - public ServiceReference CreateServiceReference(StatefulService service, string listenerName = null) - { - return new ServiceReference(); - } - } - public class MockSubscriberStatelessServiceBase : SubscriberStatelessServiceBase { public bool MethodCalled { get; private set; } - internal new IEnumerable> Handlers => base.Handlers.Values; - /// - public MockSubscriberStatelessServiceBase(StatelessServiceContext serviceContext, ISubscriberServiceHelper subscriberServiceHelper = null) : base(serviceContext, subscriberServiceHelper) + public MockSubscriberStatelessServiceBase(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext, brokerClient) { } diff --git a/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs b/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs new file mode 100644 index 0000000..2357eef --- /dev/null +++ b/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs @@ -0,0 +1,81 @@ +using System; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Actors; +using Microsoft.ServiceFabric.Services.Client; +using ServiceFabric.PubSubActors.Helpers; +using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.State; + +namespace ServiceFabric.PubSubActors.Tests +{ + public class MockBrokerServiceLocator : IBrokerServiceLocator + { + public Task LocateAsync() + { + return Task.FromResult(new Uri("mockUri")); + } + + public Task RegisterAsync(Uri brokerServiceName) + { + return Task.CompletedTask; + } + + public Task GetPartitionForMessageAsync(string messageTypeName, Uri brokerServiceName) + { + return Task.FromResult(null); + } + + public Task GetPartitionForMessageAsync(object message, Uri brokerServiceName) + { + return Task.FromResult(null); + } + + public Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName = null) + { + return Task.FromResult(new MockBrokerService()); + } + + public Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName = null) + { + return Task.FromResult(new MockBrokerService()); + } + } + + public class MockBrokerService : IBrokerService + { + public Task RegisterSubscriberAsync(ActorReference actor, string messageTypeName) + { + return Task.CompletedTask; + } + + public Task UnregisterSubscriberAsync(ActorReference actor, string messageTypeName, bool flushQueue) + { + return Task.CompletedTask; + } + + public Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName) + { + return Task.CompletedTask; + } + + public Task UnregisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, bool flushQueue) + { + return Task.CompletedTask; + } + + public Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName) + { + return Task.CompletedTask; + } + + public Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName, bool flushQueue) + { + return Task.CompletedTask; + } + + public Task PublishMessageAsync(MessageWrapper message) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/BrokerServiceBase.cs b/ServiceFabric.PubSubActors/BrokerServiceBase.cs index 5891211..1ee4913 100644 --- a/ServiceFabric.PubSubActors/BrokerServiceBase.cs +++ b/ServiceFabric.PubSubActors/BrokerServiceBase.cs @@ -13,17 +13,15 @@ using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Helpers; using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.PublisherActors; using ServiceFabric.PubSubActors.State; using ServiceFabric.PubSubActors.SubscriberServices; namespace ServiceFabric.PubSubActors { /// - /// Base class for a that serves as a Broker that accepts messages - /// from Actors & Services calling - /// and forwards them to Actors and Services. - /// Every message type is mapped to one of the partitions of this service. + /// Base class for a that serves as a Broker that accepts messages from Actors & + /// Services and forwards them to Actors and + /// Services. Every message type is mapped to one of the partitions of this service. /// public abstract class BrokerServiceBase : StatefulService, IBrokerService { @@ -119,7 +117,7 @@ protected BrokerServiceBase(StatefulServiceContext serviceContext, public async Task RegisterSubscriberAsync(ActorReference actor, string messageTypeName, string routingKey) { var actorReference = new ActorReferenceWrapper(actor, routingKey); - await RegisterSubscriberAsync(actorReference, messageTypeName); + await SubscribeAsync(actorReference, messageTypeName); } /// /// Unregisters an Actor as a subscriber for messages. @@ -130,7 +128,7 @@ public async Task RegisterSubscriberAsync(ActorReference actor, string messageTy public async Task UnregisterSubscriberAsync(ActorReference actor, string messageTypeName, bool flushQueue) { var actorReference = new ActorReferenceWrapper(actor); - await UnregisterSubscriberAsync(actorReference, messageTypeName); + await UnsubscribeAsync(actorReference, messageTypeName, flushQueue); } /// /// Registers a service as a subscriber for messages. @@ -141,7 +139,7 @@ public async Task UnregisterSubscriberAsync(ActorReference actor, string message public async Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, string routingKey) { var serviceReference = new ServiceReferenceWrapper(service, routingKey); - await RegisterSubscriberAsync(serviceReference, messageTypeName); + await SubscribeAsync(serviceReference, messageTypeName); } /// /// Unregisters a service as a subscriber for messages. @@ -149,11 +147,10 @@ public async Task RegisterServiceSubscriberAsync(ServiceReference service, strin /// Full type name of message object. /// Reference to the actor to unsubscribe. /// Publish any remaining messages. - public async Task UnregisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, - bool flushQueue) + public async Task UnregisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, bool flushQueue) { var serviceReference = new ServiceReferenceWrapper(service); - await UnregisterSubscriberAsync(serviceReference, messageTypeName); + await UnsubscribeAsync(serviceReference, messageTypeName, flushQueue); } /// /// Takes a published message and forwards it (indirectly) to all Subscribers. @@ -209,7 +206,7 @@ protected override async Task RunAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - //process messages for given time, then allow other transactions to enqueue messages + //process messages for given time, then allow other transactions to enqueue messages var cts = new CancellationTokenSource(MaxProcessingPeriod); var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancellationToken); try @@ -347,7 +344,7 @@ protected void ServiceEventSourceMessage(string message, [CallerMemberName] stri /// /// /// - private async Task RegisterSubscriberAsync(ReferenceWrapper reference, string messageTypeName) + public async Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName) { await WaitForInitializeAsync(CancellationToken.None); @@ -384,15 +381,16 @@ await TimeoutRetryHelper.ExecuteInTransaction(StateManager, async (tx, token, st } protected abstract Task CreateQueueAsync(ITransaction tx, string queueName); - + /// /// Unregisters a Service or Actor as subscriber for messages of type /// /// /// + /// /// - private async Task UnregisterSubscriberAsync(ReferenceWrapper reference, string messageTypeName) + public async Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName, bool flushQueue) { await WaitForInitializeAsync(CancellationToken.None); diff --git a/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs new file mode 100644 index 0000000..16b9e65 --- /dev/null +++ b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Fabric; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Actors; +using Microsoft.ServiceFabric.Actors.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; +using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.State; + +namespace ServiceFabric.PubSubActors.Helpers +{ + public class BrokerClient : IBrokerClient + { + private readonly IBrokerServiceLocator _brokerServiceLocator; + + /// + /// The message types that this service subscribes to and their respective handler methods. + /// + protected Dictionary> Handlers { get; set; } = new Dictionary>(); + + public BrokerClient(IBrokerServiceLocator brokerServiceLocator = null) + { + _brokerServiceLocator = brokerServiceLocator ?? new BrokerServiceLocator(); + } + + /// + /// Publish a message. + /// + /// + /// + public async Task PublishMessageAsync(object message) + { + var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(message); + await brokerService.PublishMessageAsync(message.CreateMessageWrapper()); + } + + /// + public Task SubscribeAsync(StatelessService service, Type messageType, Func handler, string listenerName = null) where T : class + { + return SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); + } + + /// + public Task SubscribeAsync(StatefulService service, Type messageType, Func handler, string listenerName = null) where T : class + { + return SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); + } + + /// + public Task SubscribeAsync(ActorBase actor, Type messageType, Func handler) where T : class + { + return SubscribeAsync(CreateReferenceWrapper(actor), messageType, handler); + } + + /// + public Task UnsubscribeAsync(StatelessService service, Type messageType, bool flush) + { + return UnsubscribeAsync(CreateReferenceWrapper(service), messageType, flush); + } + + /// + public Task UnsubscribeAsync(StatefulService service, Type messageType, bool flush) + { + return UnsubscribeAsync(CreateReferenceWrapper(service), messageType, flush); + } + + /// + public Task UnsubscribeAsync(ActorBase actor, Type messageType, bool flush) + { + return UnsubscribeAsync(CreateReferenceWrapper(actor), messageType, flush); + } + + public Task ProcessMessageAsync(MessageWrapper messageWrapper) + { + var messageType = Assembly.Load(messageWrapper.Assembly).GetType(messageWrapper.MessageType, true); + + while (messageType != null) + { + if (Handlers.TryGetValue(messageType, out var handler)) + { + return handler(messageWrapper.CreateMessage()); + } + messageType = messageType.BaseType; + } + + return Task.FromResult(true); + } + + /// + /// Registers a Service or Actor as a subscriber for messages of type with the . + /// + /// + private async Task SubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType, Func handler) where T : class + { + Handlers[messageType] = message => handler((T)message); + var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.FullName); + await brokerService.SubscribeAsync(referenceWrapper, messageType.FullName); + } + + /// + /// Unregisters a Service or Actor as a subscriber for messages of type with the . + /// + /// + private async Task UnsubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType, bool flushQueue) + { + var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.FullName); + await brokerService.UnsubscribeAsync(referenceWrapper, messageType.FullName, flushQueue); + } + + /// + /// Create a ReferenceWrapper object given this StatelessService. + /// + /// + /// + /// + /// + private ReferenceWrapper CreateReferenceWrapper(StatelessService service, string listenerName = null) + { + if (service == null) throw new ArgumentNullException(nameof(service)); + var servicePartition = GetPropertyValue(service, "Partition"); + return new ServiceReferenceWrapper(CreateServiceReference(service.Context, servicePartition.PartitionInfo, listenerName)); + } + + /// + /// Create a ReferenceWrapper object given this StatefulService. + /// + /// + /// + /// + /// + private ReferenceWrapper CreateReferenceWrapper(StatefulService service, string listenerName = null) + { + if (service == null) throw new ArgumentNullException(nameof(service)); + var servicePartition = GetPropertyValue(service, "Partition"); + return new ServiceReferenceWrapper(CreateServiceReference(service.Context, servicePartition.PartitionInfo, listenerName)); + } + + /// + /// Create a ReferenceWrapper object given this Actor. + /// + /// + /// + /// + private ReferenceWrapper CreateReferenceWrapper(ActorBase actor) + { + if (actor == null) throw new ArgumentNullException(nameof(actor)); + return new ActorReferenceWrapper(ActorReference.Get(actor)); + } + + /// + /// Creates a for the provided service context and partition info. + /// + /// + /// + /// (optional) The name of the listener that is used to communicate with the service + /// + private ServiceReference CreateServiceReference(ServiceContext context, ServicePartitionInformation info, string listenerName = null) + { + var serviceReference = new ServiceReference + { + ApplicationName = context.CodePackageActivationContext.ApplicationName, + PartitionKind = info.Kind, + ServiceUri = context.ServiceName, + PartitionGuid = context.PartitionId, + ListenerName = listenerName + }; + + if (info is Int64RangePartitionInformation longInfo) + { + serviceReference.PartitionKey = longInfo.LowKey; + } + else if (info is NamedPartitionInformation stringInfo) + { + serviceReference.PartitionName = stringInfo.Name; + } + + return serviceReference; + } + + private TProperty GetPropertyValue(TClass instance, string propertyName) + { + return (TProperty)(typeof(TClass) + .GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic)? + .GetValue(instance) ?? throw new ArgumentNullException($"Unable to find property: '{propertyName}' on: '{instance}'")); + } + } +} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs b/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs index a79e7b3..6231857 100644 --- a/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs +++ b/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs @@ -14,6 +14,7 @@ public class BrokerServiceLocator : IBrokerServiceLocator { private readonly IHashingHelper _hashingHelper; private static ServicePartitionList _cachedPartitions; + private static Uri _cachedBrokerUri; private readonly FabricClient _fabricClient; private const string _brokerName = nameof(BrokerService); private readonly IServiceProxyFactory _serviceProxyFactory; @@ -52,6 +53,11 @@ public async Task RegisterAsync(Uri brokerServiceName) /// public async Task LocateAsync() { + if (_cachedBrokerUri != null) + { + return _cachedBrokerUri; + } + try { // check current context @@ -62,8 +68,8 @@ public async Task LocateAsync() { // try to find broker name in other application types bool hasPages = true; - - var query = new ApplicationQueryDescription() { MaxResults = 50 }; + + var query = new ApplicationQueryDescription { MaxResults = 50 }; while (hasPages) { @@ -77,20 +83,24 @@ public async Task LocateAsync() { var found = await LocateAsync(app.ApplicationName); if (found != null) - return found; + { + _cachedBrokerUri = found; + return _cachedBrokerUri; + } } } } else { - return new Uri(property.GetValue()); + _cachedBrokerUri = new Uri(property.GetValue()); + return _cachedBrokerUri; } } catch { ; } - return null; + throw new InvalidOperationException("No brokerService was discovered in the cluster."); } private async Task LocateAsync(Uri applicationName) @@ -121,7 +131,7 @@ public async Task GetPartitionForMessageAsync(string messag { if (_cachedPartitions == null) { - _cachedPartitions = await _fabricClient.QueryManager.GetPartitionListAsync(brokerServiceName); + _cachedPartitions = await _fabricClient.QueryManager.GetPartitionListAsync(brokerServiceName ?? await LocateAsync()); } int hashCode; @@ -146,23 +156,30 @@ public async Task GetPartitionForMessageAsync(string messag public Task GetPartitionForMessageAsync(object message, Uri brokerServiceName) { if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) throw new ArgumentNullException(nameof(brokerServiceName)); - string messageTypeName = message.GetType().FullName; return GetPartitionForMessageAsync(messageTypeName, brokerServiceName); } /// - public async Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName) + public async Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName = null) { + if (message == null) throw new ArgumentNullException(nameof(message)); + if (brokerServiceName == null) + { + brokerServiceName = await LocateAsync(); + } var resolvedPartition = await GetPartitionForMessageAsync(message, brokerServiceName); var brokerService = _serviceProxyFactory.CreateServiceProxy(brokerServiceName, resolvedPartition, listenerName: BrokerServiceBase.ListenerName); return brokerService; } /// - public async Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName) + public async Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName = null) { + if (brokerServiceName == null) + { + brokerServiceName = await LocateAsync(); + } var resolvedPartition = await GetPartitionForMessageAsync(messageTypeName, brokerServiceName); var brokerService = _serviceProxyFactory.CreateServiceProxy(brokerServiceName, resolvedPartition, listenerName: BrokerServiceBase.ListenerName); return brokerService; diff --git a/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs b/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs new file mode 100644 index 0000000..d633211 --- /dev/null +++ b/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs @@ -0,0 +1,81 @@ +using System; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Actors.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; +using ServiceFabric.PubSubActors.Interfaces; + +namespace ServiceFabric.PubSubActors.Helpers +{ + public interface IBrokerClient + { + /// + /// Publish a message. + /// + /// + /// + Task PublishMessageAsync(object message); + + /// + /// Registers this StatelessService as a subscriber for messages of type with the . + /// + /// + /// + /// + /// + /// + Task SubscribeAsync(StatelessService service, Type messageType, Func handler, string listenerName = null) where T : class; + + /// + /// Registers this StatefulService as a subscriber for messages of type with the . + /// + /// + /// + /// + /// + /// + Task SubscribeAsync(StatefulService service, Type messageType, Func handler, string listenerName = null) where T : class; + + /// + /// Registers this Actor as a subscriber for messages of type with the . + /// + /// + /// + /// + /// + Task SubscribeAsync(ActorBase actor, Type messageType, Func handler) where T : class; + + /// + /// Unregisters this StatelessService as a subscriber for messages of type with the . + /// + /// + /// + /// + /// + Task UnsubscribeAsync(StatelessService service, Type messageType, bool flush); + + /// + /// Unregisters this StatefulService as a subscriber for messages of type with the . + /// + /// + /// + /// + /// + Task UnsubscribeAsync(StatefulService service, Type messageType, bool flush); + + /// + /// Unregisters this Actor as a subscriber for messages of type with the . + /// + /// + /// + /// + /// + Task UnsubscribeAsync(ActorBase actor, Type messageType, bool flush); + + /// + /// Given a , call the handler given for that type when was called. + /// + /// + /// + Task ProcessMessageAsync(MessageWrapper messageWrapper); + } +} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs b/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs index 2ef415a..f4f1339 100644 --- a/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs +++ b/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs @@ -41,7 +41,7 @@ public interface IBrokerServiceLocator /// /// Uri of BrokerService instance /// - Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName); + Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName = null); /// /// Gets the instance for the provided @@ -49,6 +49,6 @@ public interface IBrokerServiceLocator /// Full type name of message object. /// Uri of BrokerService instance /// - Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName); + Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName = null); } } \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs b/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs new file mode 100644 index 0000000..28b6571 --- /dev/null +++ b/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace ServiceFabric.PubSubActors.Helpers +{ + /// + /// Enables the below extension method that use the to discover message handler methods. + /// + public interface ISubscriber + { + } + + /// + /// Marks a service method as being capable of receiving messages. + /// Follows convention that method has signature 'Task MethodName(MessageType message)' + /// Polymorphism is supported. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public class SubscribeAttribute : Attribute + { + } + + public static class SubscriberExtensions + { + public static Dictionary> DiscoverMessageHandlers(this ISubscriber service) + { + var handlers = new Dictionary>(); + var taskType = typeof(Task); + var methods = service.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + foreach (var method in methods) + { + var subscribeAttribute = method.GetCustomAttributes(typeof(SubscribeAttribute), false) + .Cast() + .SingleOrDefault(); + + if (subscribeAttribute == null) continue; + + var parameters = method.GetParameters(); + if (parameters.Length != 1 || !taskType.IsAssignableFrom(method.ReturnType)) continue; + + handlers[parameters[0].ParameterType] = m => (Task) method.Invoke(service, new[] {m}); + } + + return handlers; + } + } +} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs b/ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs index bfc9036..a932937 100644 --- a/ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs +++ b/ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs @@ -138,24 +138,7 @@ public async Task SubscribeAsync(ServiceReference serviceReference, IEnumerable< /// public Dictionary> DiscoverMessageHandlers(T handlerClass) where T : class { - Dictionary> handlers = new Dictionary>(); - Type taskType = typeof(Task); - var methods = handlerClass.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - foreach (var method in methods) - { - var subscribeAttribute = method.GetCustomAttributes(typeof(SubscribeAttribute), false) - .Cast() - .SingleOrDefault(); - - if (subscribeAttribute == null) continue; - - var parameters = method.GetParameters(); - if (parameters.Length != 1 || !taskType.IsAssignableFrom(method.ReturnType)) continue; - - handlers[parameters[0].ParameterType] = m => (Task) method.Invoke(handlerClass, new[] {m}); - } - - return handlers; + return ((ISubscriber)handlerClass).DiscoverMessageHandlers(); } /// @@ -255,14 +238,4 @@ protected void LogMessage(string message, [CallerMemberName] string caller = "un _logCallback?.Invoke($"{caller} - {message}"); } } - - /// - /// Marks a service method as being capable of receiving messages. - /// Follows convention that method has signature 'Task MethodName(MessageType message)' - /// Polymorphism is supported. - /// - [AttributeUsage(AttributeTargets.Method, Inherited = false)] - public class SubscribeAttribute : Attribute - { - } } \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/IBrokerService.cs b/ServiceFabric.PubSubActors/IBrokerService.cs index 2c87e5e..4fee362 100644 --- a/ServiceFabric.PubSubActors/IBrokerService.cs +++ b/ServiceFabric.PubSubActors/IBrokerService.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Remoting; +using ServiceFabric.PubSubActors.State; namespace ServiceFabric.PubSubActors { @@ -40,6 +41,21 @@ public interface IBrokerService : IService /// Publish any remaining messages. Task UnregisterServiceSubscriberAsync(Interfaces.ServiceReference service, string messageTypeName, bool flushQueue); + /// + /// Registers a Service or Actor as a subscriber for messages. + /// + /// Reference to the service or actor to register. + /// The full type name of the message to subscribe to. + Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName); + + /// + /// Unregisters a Service or Actor as a subscriber for messages. + /// + /// The full type name of the message to subscribe to. + /// Reference to the service or actor to unregister. + /// Publish any remaining messages. + Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName, bool flushQueue); + /// /// Takes a published message and forwards it (indirectly) to all Subscribers. /// diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs index ba533b7..d1b51cf 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Fabric; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; @@ -12,14 +13,14 @@ namespace ServiceFabric.PubSubActors.SubscriberServices { - public class SubscriberStatefulServiceBase : StatefulService, ISubscriberService + public class SubscriberStatefulServiceBase : StatefulService, ISubscriberService, ISubscriber { - private readonly ISubscriberServiceHelper _subscriberServiceHelper; + private readonly IBrokerClient _brokerClient; /// - /// The message types that this service subscribes to and their respective handler methods. + /// When Set, this callback will be used to log messages to. /// - protected Dictionary> Handlers { get; set; } = new Dictionary>(); + protected Action Logger { get; set; } /// /// Set the Listener name so the remote Broker can find this service when there are multiple listeners available. @@ -30,11 +31,11 @@ public class SubscriberStatefulServiceBase : StatefulService, ISubscriberService /// Creates a new instance using the provided context. /// /// - /// - protected SubscriberStatefulServiceBase(StatefulServiceContext serviceContext, ISubscriberServiceHelper subscriberServiceHelper = null) + /// + protected SubscriberStatefulServiceBase(StatefulServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext) { - _subscriberServiceHelper = subscriberServiceHelper ?? new SubscriberServiceHelper(new BrokerServiceLocator()); + _brokerClient = brokerClient ?? new BrokerClient(); } /// @@ -42,18 +43,17 @@ protected SubscriberStatefulServiceBase(StatefulServiceContext serviceContext, I /// /// /// - /// + /// protected SubscriberStatefulServiceBase(StatefulServiceContext serviceContext, - IReliableStateManagerReplica2 reliableStateManagerReplica, ISubscriberServiceHelper subscriberServiceHelper = null) + IReliableStateManagerReplica2 reliableStateManagerReplica, IBrokerClient brokerClient = null) : base(serviceContext, reliableStateManagerReplica) { - _subscriberServiceHelper = subscriberServiceHelper ?? new SubscriberServiceHelper(new BrokerServiceLocator()); + _brokerClient = brokerClient ?? new BrokerClient(); } /// protected override Task OnOpenAsync(ReplicaOpenMode openMode, CancellationToken cancellationToken) { - Handlers = _subscriberServiceHelper.DiscoverMessageHandlers(this); return Subscribe(); } @@ -64,7 +64,7 @@ protected override Task OnOpenAsync(ReplicaOpenMode openMode, CancellationToken /// public virtual Task ReceiveMessageAsync(MessageWrapper messageWrapper) { - return _subscriberServiceHelper.ProccessMessageAsync(messageWrapper, Handlers); + return _brokerClient.ProcessMessageAsync(messageWrapper); } /// @@ -72,10 +72,20 @@ public virtual Task ReceiveMessageAsync(MessageWrapper messageWrapper) /// This method can be overriden to subscribe manually based on custom logic. /// /// - protected virtual Task Subscribe() + protected virtual async Task Subscribe() { - var serviceReference = _subscriberServiceHelper.CreateServiceReference(this, ListenerName); - return _subscriberServiceHelper.SubscribeAsync(serviceReference, Handlers.Keys); + foreach (var handler in this.DiscoverMessageHandlers()) + { + try + { + await _brokerClient.SubscribeAsync(this, handler.Key, handler.Value, ListenerName); + LogMessage($"Registered Service:'{Context.ServiceName}' as Subscriber of {handler.Key}."); + } + catch (Exception ex) + { + LogMessage($"Failed to register Service:'{Context.ServiceName}' as Subscriber of {handler.Key}. Error:'{ex.Message}'."); + } + } } /// @@ -83,5 +93,15 @@ protected override IEnumerable CreateServiceReplicaListe { return this.CreateServiceRemotingReplicaListeners(); } + + /// + /// Outputs the provided message to the if it's configured. + /// + /// + /// + protected void LogMessage(string message, [CallerMemberName] string caller = "unknown") + { + Logger?.Invoke($"{caller} - {message}"); + } } } \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs index 04d11c8..9d86756 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs @@ -6,6 +6,7 @@ using ServiceFabric.PubSubActors.Interfaces; using System.Collections.Generic; using System.Fabric; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -15,33 +16,29 @@ namespace ServiceFabric.PubSubActors.SubscriberServices /// Base class for a that serves as a subscriber of messages from the broker. /// Subscribe to message types and define a handler callback by using the . /// - public abstract class SubscriberStatelessServiceBase : StatelessService, ISubscriberService + public abstract class SubscriberStatelessServiceBase : StatelessService, ISubscriberService, ISubscriber { - private readonly ISubscriberServiceHelper _subscriberServiceHelper; + private readonly IBrokerClient _brokerClient; /// - /// The message types that this service subscribes to and their respective handler methods. + /// When Set, this callback will be used to log messages to. /// - protected Dictionary> Handlers { get; set; } = new Dictionary>(); + protected Action Logger { get; set; } /// /// Set the Listener name so the remote Broker can find this service when there are multiple listeners available. /// protected string ListenerName { get; set; } - protected SubscriberStatelessServiceBase(StatelessServiceContext serviceContext, ISubscriberServiceHelper subscriberServiceHelper = null) + protected SubscriberStatelessServiceBase(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext) { - _subscriberServiceHelper = subscriberServiceHelper ?? new SubscriberServiceHelper(new BrokerServiceLocator()); + _brokerClient = brokerClient ?? new BrokerClient(); } - /// - /// Subscribes to all message types that have a handler registered using the . - /// - /// + /// protected override Task OnOpenAsync(CancellationToken cancellationToken) { - Handlers = _subscriberServiceHelper.DiscoverMessageHandlers(this); return Subscribe(); } @@ -52,7 +49,7 @@ protected override Task OnOpenAsync(CancellationToken cancellationToken) /// public virtual Task ReceiveMessageAsync(MessageWrapper messageWrapper) { - return _subscriberServiceHelper.ProccessMessageAsync(messageWrapper, Handlers); + return _brokerClient.ProcessMessageAsync(messageWrapper); } /// @@ -60,10 +57,20 @@ public virtual Task ReceiveMessageAsync(MessageWrapper messageWrapper) /// This method can be overriden to subscribe manually based on custom logic. /// /// - protected virtual Task Subscribe() + protected virtual async Task Subscribe() { - var serviceReference = _subscriberServiceHelper.CreateServiceReference(this, ListenerName); - return _subscriberServiceHelper.SubscribeAsync(serviceReference, Handlers.Keys); + foreach (var handler in this.DiscoverMessageHandlers()) + { + try + { + await _brokerClient.SubscribeAsync(this, handler.Key, handler.Value, ListenerName); + LogMessage($"Registered Service:'{Context.ServiceName}' as Subscriber of {handler.Key}."); + } + catch (Exception ex) + { + LogMessage($"Failed to register Service:'{Context.ServiceName}' as Subscriber of {handler.Key}. Error:'{ex.Message}'."); + } + } } /// @@ -71,5 +78,15 @@ protected override IEnumerable CreateServiceInstanceLis { return this.CreateServiceRemotingInstanceListeners(); } + + /// + /// Outputs the provided message to the if it's configured. + /// + /// + /// + protected void LogMessage(string message, [CallerMemberName] string caller = "unknown") + { + Logger?.Invoke($"{caller} - {message}"); + } } } \ No newline at end of file From e442f75be0d6a8a03478c5ac8b8ecf15405989e2 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Wed, 27 Feb 2019 14:21:14 -0800 Subject: [PATCH 02/11] removed BrokerActor and RelayBrokerActor --- README.md | 2 +- .../IBrokerActor.cs | 49 --- .../IRelayBrokerActor.cs | 44 --- ServiceFabric.PubSubActors/BrokerActor.cs | 311 ------------------ .../PublisherActorExtensions.cs | 47 +-- .../PublisherServiceExtensions.cs | 67 ---- .../RelayBrokerActor.cs | 41 --- .../State/BrokerActorState.cs | 27 -- .../SubscriberActorExtensions.cs | 90 ----- .../SubscriberServiceExtensions.cs | 216 +----------- 10 files changed, 4 insertions(+), 890 deletions(-) delete mode 100644 ServiceFabric.PubSubActors.Interfaces/IBrokerActor.cs delete mode 100644 ServiceFabric.PubSubActors.Interfaces/IRelayBrokerActor.cs delete mode 100644 ServiceFabric.PubSubActors/BrokerActor.cs delete mode 100644 ServiceFabric.PubSubActors/RelayBrokerActor.cs delete mode 100644 ServiceFabric.PubSubActors/State/BrokerActorState.cs diff --git a/README.md b/README.md index d0e6a16..cafd9d6 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ https://www.nuget.org/packages/ServiceFabric.PubSubActors.Interfaces (for Actor Using this package you can reliably send messages from Publishers (Actors/Services) to many Subscribers (Actors/Services). -This is done using an intermediate, which is the BrokerActor or BrokerService. +This is done using an intermediate, which is the BrokerService. Add this package to all Reliable Actor & Service projects that participate in the pub/sub messaging. Add the package 'ServiceFabric.PubSubActors.Interfaces' to all (*ReliableActor).Interfaces projects. diff --git a/ServiceFabric.PubSubActors.Interfaces/IBrokerActor.cs b/ServiceFabric.PubSubActors.Interfaces/IBrokerActor.cs deleted file mode 100644 index 298d8d5..0000000 --- a/ServiceFabric.PubSubActors.Interfaces/IBrokerActor.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Runtime; -using System.Threading.Tasks; - -namespace ServiceFabric.PubSubActors.Interfaces -{ - /// - /// Acts as a registry for Subscriber Actors and Services that publishing Actors and Services can publish to. - /// Don't forget to mark implementing classes with - /// the attribute like: [ActorService(Name = nameof(IBrokerActor))] - /// - [Obsolete("This interface will be removed in the next major upgrade. Use the BrokerService instead.")] - public interface IBrokerActor : IActor - { - /// - /// Registers an Actor as a subscriber for messages. - /// - /// Reference to the actor to register. - Task RegisterSubscriberAsync(ActorReference actor); - - /// - /// Unregisters an Actor as a subscriber for messages. - /// - /// Reference to the actor to unregister. - /// Publish any remaining messages. - Task UnregisterSubscriberAsync(ActorReference actor, bool flushQueue); - - /// - /// Registers a service as a subscriber for messages. - /// - /// Reference to the actor to register. - Task RegisterServiceSubscriberAsync(ServiceReference service); - - /// - /// Unregisters a service as a subscriber for messages. - /// - /// Reference to the actor to unregister. - /// Publish any remaining messages. - Task UnregisterServiceSubscriberAsync(ServiceReference actor, bool flushQueue); - - /// - /// Takes a published message and forwards it (indirectly) to all Subscribers. - /// - /// The message to publish - /// - Task PublishMessageAsync(MessageWrapper message); - } -} diff --git a/ServiceFabric.PubSubActors.Interfaces/IRelayBrokerActor.cs b/ServiceFabric.PubSubActors.Interfaces/IRelayBrokerActor.cs deleted file mode 100644 index ecee74e..0000000 --- a/ServiceFabric.PubSubActors.Interfaces/IRelayBrokerActor.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Runtime; -using System; -using System.Threading.Tasks; - -namespace ServiceFabric.PubSubActors.Interfaces -{ - /// - /// Acts as a relay registry for Subscriber Actors that -Actors can publish to. - /// Don't forget to mark implementing classes with - /// the attribute like: [ActorService(Name = nameof(IRelayBrokerActor))] - /// - [Obsolete("This interface will be removed in the next major upgrade. Use the BrokerService instead.")] - public interface IRelayBrokerActor : ISubscriberActor - { - /// - /// Registers an Actor as a subscriber for messages. - /// - /// Reference to the actor to register. - Task RegisterSubscriberAsync(ActorReference actor); - - /// - /// Unregisters an Actor as a subscriber for messages. - /// - /// Reference to the actor to unregister. - /// Publish any remaining messages. - Task UnregisterSubscriberAsync(ActorReference actor, bool flushQueue); - - /// - /// Registers a service as a subscriber for messages. - /// - /// Reference to the actor to register. - Task RegisterServiceSubscriberAsync(ServiceReference service); - - /// - /// Unregisters a service as a subscriber for messages. - /// - /// Reference to the actor to unregister. - /// Publish any remaining messages. - Task UnregisterServiceSubscriberAsync(ServiceReference actor, bool flushQueue); - - - } -} diff --git a/ServiceFabric.PubSubActors/BrokerActor.cs b/ServiceFabric.PubSubActors/BrokerActor.cs deleted file mode 100644 index 83758df..0000000 --- a/ServiceFabric.PubSubActors/BrokerActor.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Runtime; -using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.PublisherActors; -using ServiceFabric.PubSubActors.State; -using ServiceFabric.PubSubActors.SubscriberServices; - -namespace ServiceFabric.PubSubActors -{ - /// - /// Base class for a Stateful Actor that serves as a Broker that accepts messages - /// from Actors & Services calling - /// and forwards them to Actors and Services. - /// Every message type results in 1 BrokerActor instance. - /// - [StatePersistence(StatePersistence.Persisted)] - [Obsolete("This class will be removed in the next major upgrade. Use the BrokerService instead.")] - public abstract class BrokerActor : Actor, IBrokerActor - { - private string _messageType; - private IActorTimer _timer; - private const string StateKey = "__state__"; - - /// - /// Initializes a new instance of - /// - /// - /// The that will host this actor instance. - /// - /// - /// The for this actor instance. - /// - protected BrokerActor(ActorService actorService, ActorId actorId) - : base(actorService, actorId) - { - } - - /// - /// Indicates the maximum size of the Dead Letter Queue for each registered . (Default: 100) - /// - protected int MaxDeadLetterCount { get; set; } = 100; - /// - /// Gets or sets the interval to wait before starting to publish messages. (Default: 5s after Activation) - /// - protected TimeSpan DueTime { get; set; } = TimeSpan.FromSeconds(5); - - /// - /// Gets or sets the interval to wait between batches of publishing messages. (Default: 5s) - /// - protected TimeSpan Period { get; set; } = TimeSpan.FromSeconds(5); - - /// - /// When Set, this callback will be used to trace Actor messages to. - /// - protected Action ActorEventSourceMessageCallback { get; set; } - - /// - /// Registers an Actor as a subscriber for messages. - /// - /// Reference to the actor to register. - public async Task RegisterSubscriberAsync(ActorReference actor) - { - if (actor == null) throw new ArgumentNullException(nameof(actor)); - - ActorEventSourceMessage($"Registering Subscriber '{actor.ServiceUri}' for messages of type '{_messageType}'"); - - var actorReference = new ActorReferenceWrapper(actor); - var state = await StateManager.GetStateAsync(StateKey); - if (!state.SubscriberMessages.ContainsKey(actorReference)) - { - state.SubscriberMessages.Add(actorReference, new Queue()); - } - } - - /// - /// Unregisters an Actor as a subscriber for messages. - /// - /// Reference to the actor to unsubscribe. - /// Publish any remaining messages. - public async Task UnregisterSubscriberAsync(ActorReference actor, bool flushQueue) - { - if (actor == null) throw new ArgumentNullException(nameof(actor)); - ActorEventSourceMessage($"Unregistering Subscriber '{actor.ServiceUri}' for messages of type '{_messageType}'"); - - var actorReference = new ActorReferenceWrapper(actor); - Queue queue; - var state = await StateManager.GetStateAsync(StateKey); - if (flushQueue && state.SubscriberMessages.TryGetValue(actorReference, out queue)) - { - await ProcessQueueAsync(new KeyValuePair>(actorReference, queue)); - } - state.SubscriberMessages.Remove(actorReference); - } - - /// - /// Registers a service as a subscriber for messages. - /// - /// Reference to the service to register. - public async Task RegisterServiceSubscriberAsync(ServiceReference service) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - - ActorEventSourceMessage($"Registering Subscriber '{service.ServiceUri}' for messages of type '{_messageType}'"); - - var serviceReference = new ServiceReferenceWrapper(service); - var state = await StateManager.GetStateAsync(StateKey); - if (!state.SubscriberMessages.ContainsKey(serviceReference)) - { - state.SubscriberMessages.Add(serviceReference, new Queue()); - } - } - - /// - /// Unregisters a service as a subscriber for messages. - /// - /// Reference to the actor to unsubscribe. - /// Publish any remaining messages. - public async Task UnregisterServiceSubscriberAsync(ServiceReference service, bool flushQueue) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - - ActorEventSourceMessage($"Unregistering Subscriber '{service.ServiceUri}' for messages of type '{_messageType}'"); - - var serviceReference = new ServiceReferenceWrapper(service); - Queue queue; - var state = await StateManager.GetStateAsync(StateKey); - if (flushQueue && state.SubscriberMessages.TryGetValue(serviceReference, out queue)) - { - await ProcessQueueAsync(new KeyValuePair>(serviceReference, queue)); - } - state.SubscriberMessages.Remove(serviceReference); - } - - /// - /// Takes a published message and forwards it (indirectly) to all Subscribers. - /// - /// The message to publish - /// - public async Task PublishMessageAsync(MessageWrapper message) - { - ActorEventSourceMessage($"Publishing message of type '{message.MessageType}'"); - var state = await StateManager.GetStateAsync(StateKey); - foreach (var actorRef in state.SubscriberMessages.Keys) - { - state.SubscriberMessages[actorRef].Enqueue(message); - } - } - - /// - /// This method is called whenever an actor is activated. - /// Creates the initial state object and starts the Message forwarding timer. - /// - protected override async Task OnActivateAsync() - { - if (Id.Kind != ActorIdKind.String) - throw new InvalidOperationException("BrokerActor can only be created using a String ID. The ID should be the Full Name of the Message Type."); - - _messageType = Id.GetStringId(); - - - if (!await StateManager.ContainsStateAsync(StateKey)) - { - // This is the first time this actor has ever been activated. - // Set the actor's initial state values. - var state = new BrokerActorState - { - SubscriberMessages = new Dictionary>(), - SubscriberDeadLetters = new Dictionary>() - }; - await StateManager.TryAddStateAsync(StateKey, state); - ActorEventSourceMessage("State initialized."); - } - - if (_timer == null) - { - _timer = RegisterTimer(async _ => - { - await ProcessQueuesAsync(); - }, null, DueTime, Period); - - ActorEventSourceMessage("Timer initialized."); - } - - } - - /// - /// This method is called right before the actor is deactivated. - /// Unregisters the timer. - /// - /// - /// A Task that represents outstanding OnDeactivateAsync operation. - /// - protected override Task OnDeactivateAsync() - { - if (_timer != null) - { - UnregisterTimer(_timer); - } - _timer = null; - - return Task.FromResult(true); - } - - /// - /// When overridden, handles an undeliverable message for listener . - /// By default, it will be added to State.ActorDeadLetters. - /// - /// - /// - protected virtual async Task HandleUndeliverableMessageAsync(ReferenceWrapper reference, MessageWrapper message) - { - var deadLetters = await GetOrAddActorDeadLetterQueueAsync(reference); - ActorEventSourceMessage($"Adding undeliverable message to Actor Dead Letter Queue (Listener: {reference.Name}, Dead Letter Queue depth:{deadLetters.Count})"); - - ValidateQueueDepth(reference, deadLetters); - deadLetters.Enqueue(message); - } - - /// - /// Returns a 'dead letter queue' for the provided ActorReference, to store undeliverable messages. - /// - /// - /// - private async Task> GetOrAddActorDeadLetterQueueAsync(ReferenceWrapper actorReference) - { - Queue actorDeadLetters; - var state = await StateManager.GetStateAsync(StateKey); - if (!state.SubscriberDeadLetters.TryGetValue(actorReference, out actorDeadLetters)) - { - actorDeadLetters = new Queue(); - state.SubscriberDeadLetters[actorReference] = actorDeadLetters; - } - - return actorDeadLetters; - } - - /// - /// Ensures the Queue depth is less than the allowed maximum. - /// - /// - /// - private void ValidateQueueDepth(ReferenceWrapper reference, Queue deadLetters) - { - var queueDepth = deadLetters.Count; - if (queueDepth > MaxDeadLetterCount) - { - ActorEventSourceMessage( - $"Dead Letter Queue for Subscriber '{reference.Name}' has {queueDepth} items, which is more than the allowed {MaxDeadLetterCount}. Clearing it."); - deadLetters.Clear(); - } - } - - /// - /// Callback that is called from a timer. Forwards all published messages to subscribers. - /// - /// - private async Task ProcessQueuesAsync() - { - var state = await StateManager.GetStateAsync(StateKey); - foreach (var actorMessageQueue in state.SubscriberMessages) - { - await ProcessQueueAsync(actorMessageQueue); - } - } - - /// - /// Forwards all published messages to one subscriber. - /// - /// - /// - private async Task ProcessQueueAsync(KeyValuePair> actorMessageQueue) - { - int messagesProcessed = 0; - - while (actorMessageQueue.Value.Count > 0) - { - var message = actorMessageQueue.Value.Peek(); - //ActorEventSourceMessage($"Publishing message to subscribed Actor {actorMessageQueue.Key.Name}"); - try - { - await actorMessageQueue.Key.PublishAsync(message); - ActorEventSourceMessage($"Published message {++messagesProcessed} of {actorMessageQueue.Value.Count} to subscribed Actor {actorMessageQueue.Key.Name}"); - actorMessageQueue.Value.Dequeue(); - } - catch (Exception ex) - { - await HandleUndeliverableMessageAsync(actorMessageQueue.Key, message); - ActorEventSourceMessage($"Suppressed error while publishing message to subscribed Actor {actorMessageQueue.Key.Name}. Error: {ex}."); - } - } - if (messagesProcessed > 0) - { - ActorEventSourceMessage($"Processed {messagesProcessed} queued messages for '{actorMessageQueue.Key.Name}'."); - } - } - - - - /// - /// Outputs the provided message to the if it's configured. - /// - /// - private void ActorEventSourceMessage(string message) - { - ActorEventSourceMessageCallback?.Invoke(message); - } - } -} diff --git a/ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs b/ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs index b6a8dae..62a55c1 100644 --- a/ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs +++ b/ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs @@ -1,6 +1,4 @@ -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Client; -using Microsoft.ServiceFabric.Actors.Runtime; +using Microsoft.ServiceFabric.Actors.Runtime; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; using ServiceFabric.PubSubActors.Interfaces; @@ -17,48 +15,7 @@ namespace ServiceFabric.PubSubActors.PublisherActors /// public static class PublisherActorExtensions { - /// - /// Publish a message. - /// - /// - /// - /// The name of the SF application that hosts the . If not provided, actor.ApplicationName will be used. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static async Task PublishMessageAsync(this ActorBase actor, object message, string applicationName = null) - { - if (actor == null) throw new ArgumentNullException(nameof(actor)); - if (message == null) throw new ArgumentNullException(nameof(message)); - - if (string.IsNullOrWhiteSpace(applicationName)) - { - applicationName = actor.ApplicationName; - } - - var brokerActor = GetBrokerActorForMessage(message, applicationName); - var wrapper = message.CreateMessageWrapper(); - await brokerActor.PublishMessageAsync(wrapper); - } - - - - /// - /// Gets the instance for the provided - /// - /// - /// - /// - private static IBrokerActor GetBrokerActorForMessage(object message, string applicationName) - { - ActorId actorId = new ActorId(message.GetType().FullName); - IBrokerActor brokerActor = ActorProxy.Create(actorId, applicationName, nameof(IBrokerActor)); - return brokerActor; - } - - - - - /////broker service code + /////broker service code private static ServicePartitionList _cachedPartitions; /// diff --git a/ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs b/ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs index fab02aa..d0c47dc 100644 --- a/ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs +++ b/ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs @@ -1,7 +1,5 @@ using System; using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Client; using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.PublisherActors; @@ -10,71 +8,6 @@ namespace ServiceFabric.PubSubActors.PublisherServices { public static class PublisherServiceExtensions { - /// - /// Publish a message. - /// - /// - /// - /// The name of the SF application that hosts the . If not provided, ServiceInitializationParameters.CodePackageActivationContext.ApplicationName will be used. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static async Task PublishMessageAsync(this StatelessService service, object message, - string applicationName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (message == null) throw new ArgumentNullException(nameof(message)); - - if (string.IsNullOrWhiteSpace(applicationName)) - { - applicationName = service.Context.CodePackageActivationContext.ApplicationName; - } - - var brokerActor = GetBrokerActorForMessage(applicationName, message); - var wrapper = message.CreateMessageWrapper(); - await brokerActor.PublishMessageAsync(wrapper); - } - - /// - /// Publish a message. - /// - /// - /// - /// The name of the SF application that hosts the . If not provided, ServiceInitializationParameters.CodePackageActivationContext.ApplicationName will be used. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static async Task PublishMessageAsync(this StatefulServiceBase service, object message, - string applicationName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (message == null) throw new ArgumentNullException(nameof(message)); - - if (string.IsNullOrWhiteSpace(applicationName)) - { - applicationName = service.Context.CodePackageActivationContext.ApplicationName; - } - - var brokerActor = GetBrokerActorForMessage(applicationName, message); - var wrapper = message.CreateMessageWrapper(); - await brokerActor.PublishMessageAsync(wrapper); - } - - /// - /// Gets the instance for the provided - /// - /// - /// - /// - private static IBrokerActor GetBrokerActorForMessage(string applicationName, object message) - { - ActorId actorId = new ActorId(message.GetType().FullName); - IBrokerActor brokerActor = ActorProxy.Create(actorId, applicationName, nameof(IBrokerActor)); - return brokerActor; - } - - - ///////broker service code - - /// /// Publish a message. /// diff --git a/ServiceFabric.PubSubActors/RelayBrokerActor.cs b/ServiceFabric.PubSubActors/RelayBrokerActor.cs deleted file mode 100644 index 0345762..0000000 --- a/ServiceFabric.PubSubActors/RelayBrokerActor.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Runtime; -using ServiceFabric.PubSubActors.Interfaces; - -namespace ServiceFabric.PubSubActors -{ - /// - /// Special implementation of that receives and forwards incoming messages. - /// - [StatePersistence(StatePersistence.Persisted)] - [Obsolete("This class will be removed in the next major upgrade. Use the BrokerService instead.")] - public class RelayBrokerActor : BrokerActor, IRelayBrokerActor - { - /// - /// Initializes a new instance of - /// - /// - /// The that will host this actor instance. - /// - /// - /// The for this actor instance. - /// - public RelayBrokerActor(ActorService actorService, ActorId actorId) - : base(actorService, actorId) - { - } - - /// - /// Publishes the received message to all registered subscribers. - /// - /// - /// - public Task ReceiveMessageAsync(MessageWrapper message) - { - message.IsRelayed = true; - return PublishMessageAsync(message); - } - } -} diff --git a/ServiceFabric.PubSubActors/State/BrokerActorState.cs b/ServiceFabric.PubSubActors/State/BrokerActorState.cs deleted file mode 100644 index 2f0539d..0000000 --- a/ServiceFabric.PubSubActors/State/BrokerActorState.cs +++ /dev/null @@ -1,27 +0,0 @@ -using ServiceFabric.PubSubActors.Interfaces; -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace ServiceFabric.PubSubActors.State -{ - /// - /// State for . Contains a regular queue and a dead letter queue for every registered listener. - /// - [Obsolete("This class will be removed in the next major upgrade. Use the BrokerService instead.")] - [DataContract] - public sealed class BrokerActorState - { - /// - /// Contains messages that could not be be sent to subscribed listeners. (has a limit) - /// - [DataMember] - public Dictionary> SubscriberDeadLetters { get; set; } - - /// - /// Contains messages to be sent to subscribed listeners. - /// - [DataMember] - public Dictionary> SubscriberMessages { get; set; } - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs b/ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs index 0e1779e..25caaf1 100644 --- a/ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs +++ b/ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Client; using Microsoft.ServiceFabric.Actors.Runtime; using ServiceFabric.PubSubActors.Interfaces; using System; @@ -13,95 +12,6 @@ namespace ServiceFabric.PubSubActors.SubscriberActors public static class SubscriberActorExtensions { /// - /// Registers this Actor as a subscriber for messages of type using a approach. - /// The relay actor will register itself as subscriber to the broker actor, creating a fan out pattern for scalability. - /// - /// The actor registering itself as a subscriber for messages of type - /// The type of message to register for (each message type has its own instance) - /// The ID of the relay broker to register with. Remember this ID in the caller, if you ever need to unregister. - /// (optional) The ID of the source to use as the source for the - /// Remember this ID in the caller, if you ever need to unregister. - /// If not specified, the default for the message type will be used. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static async Task RegisterMessageTypeWithRelayBrokerAsync(this ActorBase actor, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId) - { - if (actor == null) throw new ArgumentNullException(nameof(actor)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (relayBrokerActorId == null) throw new ArgumentNullException(nameof(relayBrokerActorId)); - - if (sourceBrokerActorId == null) - { - sourceBrokerActorId = new ActorId(messageType.FullName); - } - IRelayBrokerActor relayBrokerActor = ActorProxy.Create(relayBrokerActorId, actor.ApplicationName, nameof(IRelayBrokerActor)); - IBrokerActor brokerActor = ActorProxy.Create(sourceBrokerActorId, actor.ApplicationName, nameof(IBrokerActor)); - - //register relay as subscriber for broker - await brokerActor.RegisterSubscriberAsync(ActorReference.Get(relayBrokerActor)); - //register caller as subscriber for relay broker - await relayBrokerActor.RegisterSubscriberAsync(ActorReference.Get(actor)); - } - - /// - /// Unregisters this Actor as a subscriber for messages of type using a approach. - /// - /// The actor registering itself as a subscriber for messages of type - /// The type of message to unregister for (each message type has its own instance) - /// The ID of the relay broker to unregister with. - /// (optional) The ID of the source that was used as the source for the - /// If not specified, the default for the message type will be used. - /// Publish any remaining messages. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static async Task UnregisterMessageTypeWithRelayBrokerAsync(this ActorBase actor, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId, bool flushQueue) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (actor == null) throw new ArgumentNullException(nameof(actor)); - if (relayBrokerActorId == null) throw new ArgumentNullException(nameof(relayBrokerActorId)); - - if (sourceBrokerActorId == null) - { - sourceBrokerActorId = new ActorId(messageType.FullName); - } - IRelayBrokerActor relayBrokerActor = ActorProxy.Create(relayBrokerActorId, actor.ApplicationName, nameof(IRelayBrokerActor)); - IBrokerActor brokerActor = ActorProxy.Create(sourceBrokerActorId, actor.ApplicationName, nameof(IBrokerActor)); - - //unregister relay as subscriber for broker - await brokerActor.UnregisterSubscriberAsync(ActorReference.Get(relayBrokerActor), flushQueue); - //unregister caller as subscriber for relay broker - await relayBrokerActor.UnregisterSubscriberAsync(ActorReference.Get(actor), flushQueue); - } - - /// - /// Registers this Actor as a subscriber for messages of type . - /// - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static async Task RegisterMessageTypeAsync(this ActorBase actor, Type messageType) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (actor == null) throw new ArgumentNullException(nameof(actor)); - ActorId actorId = new ActorId(messageType.FullName); - IBrokerActor brokerActor = ActorProxy.Create(actorId, actor.ApplicationName, nameof(IBrokerActor)); - await brokerActor.RegisterSubscriberAsync(ActorReference.Get(actor)); - } - - /// - /// Unregisters this Actor as a subscriber for messages of type . - /// - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static async Task UnregisterMessageTypeAsync(this ActorBase actor, Type messageType, bool flushQueue) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (actor == null) throw new ArgumentNullException(nameof(actor)); - ActorId actorId = new ActorId(messageType.FullName); - IBrokerActor brokerActor = ActorProxy.Create(actorId, actor.ApplicationName, nameof(IBrokerActor)); - await brokerActor.UnregisterSubscriberAsync(ActorReference.Get(actor), flushQueue); - } - - /// /// Registers this Actor as a subscriber for messages of type with the . /// /// diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs index bad64ca..e83f31b 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs @@ -1,6 +1,4 @@ -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Client; -using Microsoft.ServiceFabric.Services.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Interfaces; using System; using System.Fabric; @@ -39,150 +37,6 @@ public static TResult Deserialize(this StatelessService service, Messag return payload; } - /// - /// Registers a service as a subscriber for messages of type . - /// - /// The service registering itself as a subscriber for messages of type - /// The type of message to register for (each message type has its own instance) - /// (optional) The name of the listener that is used to communicate with the service - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task RegisterMessageTypeAsync(this StatefulServiceBase service, Type messageType, string listenerName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - return RegisterMessageTypeAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, listenerName); - } - - /// - /// Registers a service as a subscriber for messages of type . - /// - /// The service registering itself as a subscriber for messages of type - /// The type of message to register for (each message type has its own instance) - /// (optional) The name of the listener that is used to communicate with the service - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task RegisterMessageTypeAsync(this StatelessService service, Type messageType, string listenerName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - return RegisterMessageTypeAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, listenerName); - } - - /// - /// Unregisters a service as a subscriber for messages of type . - /// - /// The service unregistering itself as a subscriber for messages of type - /// The type of message to unregister for (each message type has its own instance) - /// Publish any remaining messages. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task UnregisterMessageTypeAsync(this StatelessService service, Type messageType, bool flushQueue) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - return UnregisterMessageTypeAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, flushQueue); - } - - /// - /// Unregisters a service as a subscriber for messages of type . - /// - /// The service unregistering itself as a subscriber for messages of type - /// The type of message to unregister for (each message type has its own instance) - /// Publish any remaining messages. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task UnregisterMessageTypeAsync(this StatefulServiceBase service, Type messageType, bool flushQueue) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - return UnregisterMessageTypeAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, flushQueue); - } - - /// - /// Registers a Service as a subscriber for messages of type using a approach. - /// The relay actor will register itself as subscriber to the broker actor, creating a fan out pattern for scalability. - /// - /// The service registering itself as a subscriber for messages of type - /// The type of message to register for (each message type has its own instance) - /// The ID of the relay broker to register with. Remember this ID in the caller, if you ever need to unregister. - /// (optional) The ID of the source to use as the source for the - /// Remember this ID in the caller, if you ever need to unregister. - /// If not specified, the default for the message type will be used. - /// (optional) The name of the listener that is used to communicate with the service - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task RegisterMessageTypeWithRelayBrokerAsync(this StatefulServiceBase service, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId, string listenerName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (relayBrokerActorId == null) throw new ArgumentNullException(nameof(relayBrokerActorId)); - - return RegisterMessageTypeWithRelayBrokerAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, relayBrokerActorId, sourceBrokerActorId, listenerName); - } - - /// - /// Registers a Service as a subscriber for messages of type using a approach. - /// The relay actor will register itself as subscriber to the broker actor, creating a fan out pattern for scalability. - /// - /// The service registering itself as a subscriber for messages of type - /// The type of message to register for (each message type has its own instance) - /// The ID of the relay broker to register with. Remember this ID in the caller, if you ever need to unregister. - /// (optional) The ID of the source to use as the source for the - /// Remember this ID in the caller, if you ever need to unregister. - /// If not specified, the default for the message type will be used. - /// (optional) The name of the listener that is used to communicate with the service - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task RegisterMessageTypeWithRelayBrokerAsync(this StatelessService service, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId, string listenerName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (relayBrokerActorId == null) throw new ArgumentNullException(nameof(relayBrokerActorId)); - - return RegisterMessageTypeWithRelayBrokerAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, relayBrokerActorId, sourceBrokerActorId, listenerName); - } - - /// - /// Unregisters a Service as a subscriber for messages of type using a approach. - /// - /// The service registering itself as a subscriber for messages of type - /// The type of message to unregister for (each message type has its own instance) - /// The ID of the relay broker to unregister with. - /// (optional) The ID of the source that was used as the source for the - /// If not specified, the default for the message type will be used. - /// Publish any remaining messages. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task UnregisterMessageTypeWithRelayBrokerAsync(this StatefulServiceBase service, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId, bool flushQueue) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (relayBrokerActorId == null) throw new ArgumentNullException(nameof(relayBrokerActorId)); - - return UnregisterMessageTypeWithRelayBrokerAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, relayBrokerActorId, sourceBrokerActorId, flushQueue); - } - - /// - /// Unregisters a Service as a subscriber for messages of type using a approach. - /// - /// The service registering itself as a subscriber for messages of type - /// The type of message to unregister for (each message type has its own instance) - /// The ID of the relay broker to unregister with. - /// (optional) The ID of the source that was used as the source for the - /// If not specified, the default for the message type will be used. - /// Publish any remaining messages. - /// - [Obsolete("This method will be removed in the next major upgrade. Use the BrokerService instead.")] - public static Task UnregisterMessageTypeWithRelayBrokerAsync(this StatelessService service, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId, bool flushQueue) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (relayBrokerActorId == null) throw new ArgumentNullException(nameof(relayBrokerActorId)); - - return UnregisterMessageTypeWithRelayBrokerAsync(service.Context, service.GetServicePartition().PartitionInfo, messageType, relayBrokerActorId, sourceBrokerActorId, flushQueue); - } - /// /// Registers this Service as a subscriber for messages of type with the . /// @@ -324,73 +178,5 @@ public static ServiceReference CreateServiceReference(ServiceContext context, Se return serviceReference; } - - /// - /// Registers a service as a subscriber for messages of type . - /// - /// - private static async Task RegisterMessageTypeAsync(ServiceContext context, ServicePartitionInformation info, Type messageType, string listenerName) - { - var serviceReference = CreateServiceReference(context, info, listenerName); - ActorId actorId = new ActorId(messageType.FullName); - IBrokerActor brokerActor = ActorProxy.Create(actorId, serviceReference.ApplicationName, nameof(IBrokerActor)); - - await brokerActor.RegisterServiceSubscriberAsync(serviceReference); - } - - /// - /// Unregisters a service as a subscriber for messages of type . - /// - /// - private static async Task UnregisterMessageTypeAsync(ServiceContext context, ServicePartitionInformation info, Type messageType, bool flushQueue) - { - var serviceReference = CreateServiceReference(context, info); - ActorId actorId = new ActorId(messageType.FullName); - IBrokerActor brokerActor = ActorProxy.Create(actorId, serviceReference.ApplicationName, nameof(IBrokerActor)); - - await brokerActor.UnregisterServiceSubscriberAsync(serviceReference, flushQueue); - } - - /// - /// Registers a service as a subscriber for messages of type using a relay broker. - /// - /// - private static async Task RegisterMessageTypeWithRelayBrokerAsync(ServiceContext context, ServicePartitionInformation info, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId, string listenerName = null) - { - var serviceReference = CreateServiceReference(context, info, listenerName); - - if (sourceBrokerActorId == null) - { - sourceBrokerActorId = new ActorId(messageType.FullName); - } - IRelayBrokerActor relayBrokerActor = ActorProxy.Create(relayBrokerActorId, serviceReference.ApplicationName, nameof(IRelayBrokerActor)); - IBrokerActor brokerActor = ActorProxy.Create(sourceBrokerActorId, serviceReference.ApplicationName, nameof(IBrokerActor)); - - //register relay as subscriber for broker - await brokerActor.RegisterSubscriberAsync(ActorReference.Get(relayBrokerActor)); - //register caller as subscriber for relay broker - await relayBrokerActor.RegisterServiceSubscriberAsync(serviceReference); - } - - /// - /// Unregisters a service as a subscriber for messages of type using a relay broker. - /// - /// - private static async Task UnregisterMessageTypeWithRelayBrokerAsync(ServiceContext context, ServicePartitionInformation info, Type messageType, ActorId relayBrokerActorId, ActorId sourceBrokerActorId, bool flushQueue) - { - var serviceReference = CreateServiceReference(context, info); - - if (sourceBrokerActorId == null) - { - sourceBrokerActorId = new ActorId(messageType.FullName); - } - IRelayBrokerActor relayBrokerActor = ActorProxy.Create(relayBrokerActorId, serviceReference.ApplicationName, nameof(IRelayBrokerActor)); - IBrokerActor brokerActor = ActorProxy.Create(sourceBrokerActorId, serviceReference.ApplicationName, nameof(IBrokerActor)); - - //register relay as subscriber for broker - await brokerActor.UnregisterSubscriberAsync(ActorReference.Get(relayBrokerActor), flushQueue); - //register caller as subscriber for relay broker - await relayBrokerActor.UnregisterServiceSubscriberAsync(serviceReference, flushQueue); - } } } From f8efd8614ccc4ac370bf74496f18687663fe45e8 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Wed, 27 Feb 2019 16:18:28 -0800 Subject: [PATCH 03/11] remove helper classes --- README.md | 13 +- .../Helpers/IPublisherActorHelper.cs | 18 -- .../Helpers/IPublisherServiceHelper.cs | 35 --- .../Helpers/ISubscriberActorHelper.cs | 22 -- .../Helpers/ISubscriberServiceHelper.cs | 80 ------ .../Helpers/PublisherActorHelper.cs | 50 ---- .../Helpers/PublisherServiceHelper.cs | 84 ------ .../Helpers/SubscriberActorHelper.cs | 67 ----- .../Helpers/SubscriberExtensions.cs | 21 +- .../Helpers/SubscriberServiceHelper.cs | 241 ------------------ .../StatefulSubscriberServiceBootstrapper.cs | 26 +- .../StatelessSubscriberServiceBootstrapper.cs | 22 +- .../SubscriberStatefulServiceBase.cs | 2 +- .../SubscriberStatelessServiceBase.cs | 2 +- 14 files changed, 47 insertions(+), 636 deletions(-) delete mode 100644 ServiceFabric.PubSubActors/Helpers/IPublisherActorHelper.cs delete mode 100644 ServiceFabric.PubSubActors/Helpers/IPublisherServiceHelper.cs delete mode 100644 ServiceFabric.PubSubActors/Helpers/ISubscriberActorHelper.cs delete mode 100644 ServiceFabric.PubSubActors/Helpers/ISubscriberServiceHelper.cs delete mode 100644 ServiceFabric.PubSubActors/Helpers/PublisherActorHelper.cs delete mode 100644 ServiceFabric.PubSubActors/Helpers/PublisherServiceHelper.cs delete mode 100644 ServiceFabric.PubSubActors/Helpers/SubscriberActorHelper.cs delete mode 100644 ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs diff --git a/README.md b/README.md index cafd9d6..51254f3 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ Now open the file SubscribingStatelessService.cs in the project 'SubscribingStat ```csharp internal sealed class SubscribingStatelessService : SubscriberStatelessServiceBase { - public SubscribingStatelessService(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext, subscriberServiceHelper) + public SubscribingStatelessService(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext, brokerClient) { } @@ -204,9 +204,9 @@ If you don't want to inherit from our base classes, you can use the `StatefulSub The code in `Program` will look like this: ```csharp - var helper = new SubscriberServiceHelper(); + var brokerClient = new BrokerClient(); ServiceRuntime.RegisterServiceAsync("SubscribingStatelessServiceType", - context => new StatelessSubscriberServiceBootstrapper(context, ctx => new SubscribingStatelessService (ctx, helper), helper).Build()) + context => new StatelessSubscriberServiceBootstrapper(context, ctx => new SubscribingStatelessService (ctx, brokerClient), brokerClient).Build()) .GetAwaiter().GetResult(); ``` @@ -215,14 +215,17 @@ The service looks like this: ```csharp internal sealed class SubscribingStatelessService : StatelessService, ISubscriberService { - public SubscribingStatelessService(StatelessServiceContext serviceContext, ISubscriberServiceHelper subscriberServiceHelper = null) : base(serviceContext, subscriberServiceHelper) + private readonly IBrokerClient _brokerClient; + + public SubscribingStatelessService(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext) { + _brokerClient = brokerClient; } public Task ReceiveMessageAsync(MessageWrapper messageWrapper) { // Automatically delegates work to annotated methods withing this class. - return _subscriberServiceHelper.ProccessMessageAsync(messageWrapper); + return _brokerClient.ProccessMessageAsync(messageWrapper); } protected override IEnumerable CreateServiceInstanceListeners() diff --git a/ServiceFabric.PubSubActors/Helpers/IPublisherActorHelper.cs b/ServiceFabric.PubSubActors/Helpers/IPublisherActorHelper.cs deleted file mode 100644 index 03e801a..0000000 --- a/ServiceFabric.PubSubActors/Helpers/IPublisherActorHelper.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors.Runtime; - -namespace ServiceFabric.PubSubActors.Helpers -{ - public interface IPublisherActorHelper - { - /// - /// Publish a message. - /// - /// - /// - /// The name of the SF Service of type . - /// - Task PublishMessageAsync(ActorBase actor, object message, Uri brokerServiceName = null); - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/IPublisherServiceHelper.cs b/ServiceFabric.PubSubActors/Helpers/IPublisherServiceHelper.cs deleted file mode 100644 index b3b1635..0000000 --- a/ServiceFabric.PubSubActors/Helpers/IPublisherServiceHelper.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Services.Runtime; - -namespace ServiceFabric.PubSubActors.Helpers -{ - public interface IPublisherServiceHelper - { - /// - /// Publish a message. - /// - /// - /// The name of a SF Service of type . - /// - Task PublishMessageAsync(object message, Uri brokerServiceName = null); - - /// - /// Publish a message. - /// - /// - /// - /// The name of a SF Service of type . - /// - Task PublishMessageAsync(StatelessService service, object message, Uri brokerServiceName = null); - - /// - /// Publish a message. - /// - /// - /// - /// The name of a SF Service of type . - /// - Task PublishMessageAsync(StatefulServiceBase service, object message, Uri brokerServiceName = null); - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/ISubscriberActorHelper.cs b/ServiceFabric.PubSubActors/Helpers/ISubscriberActorHelper.cs deleted file mode 100644 index 2c797c9..0000000 --- a/ServiceFabric.PubSubActors/Helpers/ISubscriberActorHelper.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors.Runtime; - -namespace ServiceFabric.PubSubActors.Helpers -{ - public interface ISubscriberActorHelper - { - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - Task RegisterMessageTypeAsync(ActorBase actor, Type messageType, Uri brokerServiceName = null, string routingKey = null); - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - Task UnregisterMessageTypeAsync(ActorBase actor, Type messageType, bool flushQueue, - Uri brokerServiceName = null); - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/ISubscriberServiceHelper.cs b/ServiceFabric.PubSubActors/Helpers/ISubscriberServiceHelper.cs deleted file mode 100644 index c6c45c1..0000000 --- a/ServiceFabric.PubSubActors/Helpers/ISubscriberServiceHelper.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Microsoft.ServiceFabric.Services.Runtime; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.SubscriberServices; - -namespace ServiceFabric.PubSubActors.Helpers -{ - public interface ISubscriberServiceHelper - { - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - Task RegisterMessageTypeAsync(StatelessService service, Type messageType, - Uri brokerServiceName = null, string listenerName = null); - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - Task UnregisterMessageTypeAsync(StatelessService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null); - - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - Task RegisterMessageTypeAsync(StatefulService service, Type messageType, - Uri brokerServiceName = null, string listenerName = null); - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - Task UnregisterMessageTypeAsync(StatefulService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null); - - /// - /// Look for Subscribe attributes and create a list of SubscriptionDefinitions to map message types to handlers. - /// - /// - /// - Dictionary> DiscoverMessageHandlers(T handlerClass) where T : class; - - /// - /// Subscribe to all message types in . - /// - /// - /// - /// - /// - Task SubscribeAsync(ServiceReference serviceReference, IEnumerable messageTypes, Uri broker = null); - - /// - /// Given the , invoke the appropriate handler in . - /// - /// - /// - /// - Task ProccessMessageAsync(MessageWrapper messageWrapper, Dictionary> handlers); - - /// - /// Creates a ServiceReference object for a StatelessService. Used for subscribing/unsubscribing. - /// - /// - /// - /// - ServiceReference CreateServiceReference(StatelessService service, string listenerName = null); - - /// - /// Creates a ServiceReference object for a StatelessService. Used for subscribing/unsubscribing. - /// - /// - /// - /// - ServiceReference CreateServiceReference(StatefulService service, string listenerName = null); - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/PublisherActorHelper.cs b/ServiceFabric.PubSubActors/Helpers/PublisherActorHelper.cs deleted file mode 100644 index ed4cb42..0000000 --- a/ServiceFabric.PubSubActors/Helpers/PublisherActorHelper.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors.Runtime; -using ServiceFabric.PubSubActors.Interfaces; - -namespace ServiceFabric.PubSubActors.Helpers -{ - /// - /// Common operations of - /// - public class PublisherActorHelper : IPublisherActorHelper - { - private readonly IBrokerServiceLocator _brokerServiceLocator; - - public PublisherActorHelper() - { - _brokerServiceLocator = new BrokerServiceLocator(); - } - - public PublisherActorHelper(IBrokerServiceLocator brokerServiceLocator) - { - _brokerServiceLocator = brokerServiceLocator; - } - - /// - /// Publish a message. - /// - /// - /// - /// The name of the SF Service of type . - /// - public async Task PublishMessageAsync(ActorBase actor, object message, Uri brokerServiceName = null) - { - if (actor == null) throw new ArgumentNullException(nameof(actor)); - if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServiceHelper.DiscoverBrokerServiceNameAsync(); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - - var wrapper = message.CreateMessageWrapper(); - var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(message, brokerServiceName); - await brokerService.PublishMessageAsync(wrapper); - } - } -} diff --git a/ServiceFabric.PubSubActors/Helpers/PublisherServiceHelper.cs b/ServiceFabric.PubSubActors/Helpers/PublisherServiceHelper.cs deleted file mode 100644 index 1bbf21b..0000000 --- a/ServiceFabric.PubSubActors/Helpers/PublisherServiceHelper.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Interfaces; - -namespace ServiceFabric.PubSubActors.Helpers -{ - public class PublisherServiceHelper : IPublisherServiceHelper - { - private readonly IBrokerServiceLocator _brokerServiceLocator; - - public PublisherServiceHelper() - { - _brokerServiceLocator = new BrokerServiceLocator(); - } - - public PublisherServiceHelper(IBrokerServiceLocator brokerServiceLocator) - { - _brokerServiceLocator = brokerServiceLocator; - } - - /// - /// Publish a message. - /// - /// - /// The name of a SF Service of type . - /// - public async Task PublishMessageAsync(object message, Uri brokerServiceName = null) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) - { - brokerServiceName = await DiscoverBrokerServiceNameAsync(); - if (brokerServiceName == null) - { - throw new InvalidOperationException( - "No brokerServiceName was provided or discovered in the current application."); - } - } - - var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(message, brokerServiceName); - var wrapper = message.CreateMessageWrapper(); - await brokerService.PublishMessageAsync(wrapper); - } - - /// - /// Publish a message. - /// - /// - /// - /// The name of a SF Service of type . - /// - public async Task PublishMessageAsync(StatelessService service, object message, - Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - await PublishMessageAsync(message, brokerServiceName); - } - - /// - /// Publish a message. - /// - /// - /// - /// The name of a SF Service of type . - /// - public async Task PublishMessageAsync(StatefulServiceBase service, object message, - Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - await PublishMessageAsync(message, brokerServiceName); - } - - /// - /// Attempts to discover the running in this Application. - /// - /// - public static Task DiscoverBrokerServiceNameAsync() - { - var locator = new BrokerServiceLocator(); - return locator.LocateAsync(); - } - } -} diff --git a/ServiceFabric.PubSubActors/Helpers/SubscriberActorHelper.cs b/ServiceFabric.PubSubActors/Helpers/SubscriberActorHelper.cs deleted file mode 100644 index 6940282..0000000 --- a/ServiceFabric.PubSubActors/Helpers/SubscriberActorHelper.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Runtime; - -namespace ServiceFabric.PubSubActors.Helpers -{ - /// - /// Common operations for Actors to become Subscribers - /// - public class SubscriberActorHelper : ISubscriberActorHelper - { - - private readonly IBrokerServiceLocator _brokerServiceLocator; - - public SubscriberActorHelper() - { - _brokerServiceLocator = new BrokerServiceLocator(); - } - - public SubscriberActorHelper(IBrokerServiceLocator brokerServiceLocator) - { - _brokerServiceLocator = brokerServiceLocator; - } - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - public async Task RegisterMessageTypeAsync(ActorBase actor, Type messageType, Uri brokerServiceName = null, string routingKey = null) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (actor == null) throw new ArgumentNullException(nameof(actor)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServiceHelper.DiscoverBrokerServiceNameAsync(); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - await brokerService.RegisterSubscriberAsync(ActorReference.Get(actor), messageType.FullName, routingKey); - } - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - public async Task UnregisterMessageTypeAsync(ActorBase actor, Type messageType, bool flushQueue, - Uri brokerServiceName = null) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (actor == null) throw new ArgumentNullException(nameof(actor)); - - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServiceHelper.DiscoverBrokerServiceNameAsync(); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - await brokerService.UnregisterSubscriberAsync(ActorReference.Get(actor), messageType.FullName, flushQueue); - } - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs b/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs index 28b6571..49c3a9b 100644 --- a/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs +++ b/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs @@ -3,16 +3,11 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; +using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.SubscriberServices; namespace ServiceFabric.PubSubActors.Helpers { - /// - /// Enables the below extension method that use the to discover message handler methods. - /// - public interface ISubscriber - { - } - /// /// Marks a service method as being capable of receiving messages. /// Follows convention that method has signature 'Task MethodName(MessageType message)' @@ -25,7 +20,17 @@ public class SubscribeAttribute : Attribute public static class SubscriberExtensions { - public static Dictionary> DiscoverMessageHandlers(this ISubscriber service) + public static Dictionary> DiscoverMessageHandlers(this ISubscriberService service) + { + return DiscoverHandlers(service); + } + + public static Dictionary> DiscoverMessageHandlers(this ISubscriberActor service) + { + return DiscoverHandlers(service); + } + + private static Dictionary> DiscoverHandlers(object service) { var handlers = new Dictionary>(); var taskType = typeof(Task); diff --git a/ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs b/ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs deleted file mode 100644 index a932937..0000000 --- a/ServiceFabric.PubSubActors/Helpers/SubscriberServiceHelper.cs +++ /dev/null @@ -1,241 +0,0 @@ -using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Interfaces; -using System; -using System.Collections.Generic; -using System.Fabric; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using ServiceFabric.PubSubActors.SubscriberServices; - -namespace ServiceFabric.PubSubActors.Helpers -{ - public class SubscriberServiceHelper : ISubscriberServiceHelper - { - /// - /// When Set, this callback will be used to trace Service messages to. - /// - private readonly Action _logCallback; - - private readonly IBrokerServiceLocator _brokerServiceLocator; - - public SubscriberServiceHelper() - { - _brokerServiceLocator = new BrokerServiceLocator(); - } - - public SubscriberServiceHelper(IBrokerServiceLocator brokerServiceLocator = null, Action logCallback = null) - { - _brokerServiceLocator = brokerServiceLocator ?? new BrokerServiceLocator(); - _logCallback = logCallback; - } - - /// - /// Registers this Service as a subscriber for messages of type with the . - /// - /// - public async Task RegisterMessageTypeAsync(StatelessService service, Type messageType, - Uri brokerServiceName = null, string listenerName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - var serviceReference = CreateServiceReference(service, listenerName); - await RegisterMessageTypeAsync(serviceReference, messageType, brokerServiceName); - } - - private async Task RegisterMessageTypeAsync(ServiceReference serviceReference, Type messageType, Uri brokerServiceName = null, string routingKey = null) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServiceHelper.DiscoverBrokerServiceNameAsync(); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - await brokerService.RegisterServiceSubscriberAsync(serviceReference, messageType.FullName, routingKey); - } - - /// - /// Unregisters this Service as a subscriber for messages of type with the . - /// - /// - public async Task UnregisterMessageTypeAsync(StatelessService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServiceHelper.DiscoverBrokerServiceNameAsync(); - if (brokerServiceName == null) - { - throw new InvalidOperationException( - "No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = - await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - var serviceReference = CreateServiceReference(service); - await brokerService.UnregisterServiceSubscriberAsync(serviceReference, messageType.FullName, flushQueue); - } - - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - public async Task RegisterMessageTypeAsync(StatefulService service, Type messageType, - Uri brokerServiceName = null, string listenerName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - var serviceReference = CreateServiceReference(service, listenerName); - await RegisterMessageTypeAsync(serviceReference, messageType, brokerServiceName); - } - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - public async Task UnregisterMessageTypeAsync(StatefulService service, Type messageType, bool flushQueue, - Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (brokerServiceName == null) - { - brokerServiceName = await _brokerServiceLocator.LocateAsync(); - if (brokerServiceName == null) - { - throw new InvalidOperationException( - "No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = - await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - var serviceReference = CreateServiceReference(service); - await brokerService.UnregisterServiceSubscriberAsync(serviceReference, messageType.FullName, flushQueue); - } - - /// - public async Task SubscribeAsync(ServiceReference serviceReference, IEnumerable messageTypes, Uri broker = null) - { - foreach (var messageType in messageTypes) - { - try - { - await RegisterMessageTypeAsync(serviceReference, messageType, broker); - LogMessage($"Registered Service:'{serviceReference.ServiceUri}' as Subscriber of {messageType}."); - } - catch (Exception ex) - { - LogMessage($"Failed to register Service:'{serviceReference.ServiceUri}' as Subscriber of {messageType}. Error:'{ex.Message}'."); - } - } - } - - /// - public Dictionary> DiscoverMessageHandlers(T handlerClass) where T : class - { - return ((ISubscriber)handlerClass).DiscoverMessageHandlers(); - } - - /// - public Task ProccessMessageAsync(MessageWrapper messageWrapper, Dictionary> handlers) - { - var messageType = Assembly.Load(messageWrapper.Assembly).GetType(messageWrapper.MessageType, true); - - while (messageType != null) - { - if (handlers.TryGetValue(messageType, out var handler)) - { - return handler(messageWrapper.CreateMessage()); - } - messageType = messageType.BaseType; - } - - return Task.FromResult(true); - } - - /// - public ServiceReference CreateServiceReference(StatelessService service, string listenerName = null) - { - return CreateServiceReference(service.Context, GetServicePartition(service).PartitionInfo, listenerName); - } - - /// - public ServiceReference CreateServiceReference(StatefulService service, string listenerName = null) - { - return CreateServiceReference(service.Context, GetServicePartition(service).PartitionInfo, listenerName); - } - - /// - /// Gets the Partition info for the provided StatefulServiceBase instance. - /// - /// - /// - private IStatefulServicePartition GetServicePartition(StatefulServiceBase serviceBase) - { - if (serviceBase == null) throw new ArgumentNullException(nameof(serviceBase)); - return (IStatefulServicePartition)serviceBase - .GetType() - .GetProperty("Partition", BindingFlags.Instance | BindingFlags.NonPublic)? - .GetValue(serviceBase) ?? throw new ArgumentNullException($"Unable to find partition information for service: {serviceBase}"); - } - - /// - /// Gets the Partition info for the provided StatelessService instance. - /// - /// - /// - private static IStatelessServicePartition GetServicePartition(StatelessService serviceBase) - { - if (serviceBase == null) throw new ArgumentNullException(nameof(serviceBase)); - return (IStatelessServicePartition)serviceBase - .GetType() - .GetProperty("Partition", BindingFlags.Instance | BindingFlags.NonPublic)? - .GetValue(serviceBase) ?? throw new ArgumentNullException($"Unable to find partition information for service: {serviceBase}"); - } - - /// - /// Creates a for the provided service context and partition info. - /// - /// - /// - /// (optional) The name of the listener that is used to communicate with the service - /// - private static ServiceReference CreateServiceReference(ServiceContext context, ServicePartitionInformation info, string listenerName = null) - { - var serviceReference = new ServiceReference - { - ApplicationName = context.CodePackageActivationContext.ApplicationName, - PartitionKind = info.Kind, - ServiceUri = context.ServiceName, - PartitionGuid = context.PartitionId, - ListenerName = listenerName - }; - - if (info is Int64RangePartitionInformation longInfo) - { - serviceReference.PartitionKey = longInfo.LowKey; - } - else if (info is NamedPartitionInformation stringInfo) - { - serviceReference.PartitionName = stringInfo.Name; - } - - return serviceReference; - } - - /// - /// Outputs the provided message to the if it's configured. - /// - /// - /// - protected void LogMessage(string message, [CallerMemberName] string caller = "unknown") - { - _logCallback?.Invoke($"{caller} - {message}"); - } - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/SubscriberServices/StatefulSubscriberServiceBootstrapper.cs b/ServiceFabric.PubSubActors/SubscriberServices/StatefulSubscriberServiceBootstrapper.cs index fc8a4ce..f21e9b9 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/StatefulSubscriberServiceBootstrapper.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/StatefulSubscriberServiceBootstrapper.cs @@ -24,7 +24,7 @@ public sealed class StatefulSubscriberServiceBootstrapper private readonly StatefulServiceContext _context; private readonly Func _serviceFactory; private readonly Action _loggingCallback; - private readonly ISubscriberServiceHelper _subscriberServiceHelper; + private readonly IBrokerClient _brokerClient; private readonly FabricClient _fabricClient; private long _filterId; private TService _service; @@ -39,19 +39,19 @@ public sealed class StatefulSubscriberServiceBootstrapper /// /// Service context. /// Builds an instance of - /// Helps with subscriptions. + /// Helps with subscriptions. /// Indicates whether the created service subscription should be removed after the service is deleted. /// Optional logging callback. public StatefulSubscriberServiceBootstrapper(StatefulServiceContext context, Func serviceFactory, - ISubscriberServiceHelper subscriberServiceHelper = null, + IBrokerClient brokerClient = null, bool autoUnsubscribe = false, Action loggingCallback = null) { _context = context ?? throw new ArgumentNullException(nameof(context)); _serviceFactory = serviceFactory ?? throw new ArgumentNullException(nameof(serviceFactory)); _loggingCallback = loggingCallback; - _subscriberServiceHelper = subscriberServiceHelper ?? new SubscriberServiceHelper(); + _brokerClient = brokerClient ?? new BrokerClient(); _fabricClient = new FabricClient(FabricClientRole.User); _fabricClient.ServiceManager.ServiceNotificationFilterMatched += ServiceNotificationFilterMatched; AutoUnsubscribe = autoUnsubscribe; @@ -121,10 +121,10 @@ private async Task RegisterSubscriptions() _loggingCallback?.Invoke($"Registering subscriptions for service '{_context.ServiceName}'."); try { - await _subscriberServiceHelper.SubscribeAsync( - _subscriberServiceHelper.CreateServiceReference(_service), - _subscriberServiceHelper.DiscoverMessageHandlers(_service).Keys) - .ConfigureAwait(false); + foreach (var subscription in _service.DiscoverMessageHandlers()) + { + await _brokerClient.SubscribeAsync(_service, subscription.Key, subscription.Value).ConfigureAwait(false); + } } catch (Exception ex) { @@ -136,13 +136,13 @@ await _subscriberServiceHelper.SubscribeAsync( private async Task UnregisterSubscriptions() { _loggingCallback?.Invoke($"Unregistering subscriptions for deleted service '{_context.ServiceName}'."); - + try { - await _subscriberServiceHelper.SubscribeAsync( - _subscriberServiceHelper.CreateServiceReference(_service), - _subscriberServiceHelper.DiscoverMessageHandlers(_service).Keys) - .ConfigureAwait(false); + foreach (var subscription in _service.DiscoverMessageHandlers()) + { + await _brokerClient.UnsubscribeAsync(_service, subscription.Key, false).ConfigureAwait(false); + } } catch (Exception ex) { diff --git a/ServiceFabric.PubSubActors/SubscriberServices/StatelessSubscriberServiceBootstrapper.cs b/ServiceFabric.PubSubActors/SubscriberServices/StatelessSubscriberServiceBootstrapper.cs index 7dde8e0..e351141 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/StatelessSubscriberServiceBootstrapper.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/StatelessSubscriberServiceBootstrapper.cs @@ -23,7 +23,7 @@ public sealed class StatelessSubscriberServiceBootstrapper { private readonly StatelessServiceContext _context; private readonly Func _serviceFactory; - private readonly ISubscriberServiceHelper _subscriberServiceHelper; + private readonly IBrokerClient _brokerClient; private readonly Action _loggingCallback; private readonly FabricClient _fabricClient; private long _filterId; @@ -44,13 +44,13 @@ public sealed class StatelessSubscriberServiceBootstrapper /// Optional logging callback. public StatelessSubscriberServiceBootstrapper(StatelessServiceContext context, Func serviceFactory, - ISubscriberServiceHelper subscriberServiceHelper = null, + IBrokerClient subscriberServiceHelper = null, bool autoUnsubscribe = false, Action loggingCallback = null) { _context = context ?? throw new ArgumentNullException(nameof(context)); _serviceFactory = serviceFactory ?? throw new ArgumentNullException(nameof(serviceFactory)); - _subscriberServiceHelper = subscriberServiceHelper ?? new SubscriberServiceHelper(); + _brokerClient = subscriberServiceHelper ?? new BrokerClient(); _fabricClient = new FabricClient(FabricClientRole.User); _fabricClient.ServiceManager.ServiceNotificationFilterMatched += ServiceNotificationFilterMatched; _loggingCallback = loggingCallback; @@ -121,10 +121,10 @@ private async Task RegisterSubscriptions() _loggingCallback?.Invoke($"Registering subscriptions for service '{_context.ServiceName}'."); try { - await _subscriberServiceHelper.SubscribeAsync( - _subscriberServiceHelper.CreateServiceReference(_service), - _subscriberServiceHelper.DiscoverMessageHandlers(_service).Keys) - .ConfigureAwait(false); + foreach (var subscription in _service.DiscoverMessageHandlers()) + { + await _brokerClient.SubscribeAsync(_service, subscription.Key, subscription.Value).ConfigureAwait(false); + } } catch (Exception ex) { @@ -139,10 +139,10 @@ private async Task UnregisterSubscriptions() try { - await _subscriberServiceHelper.SubscribeAsync( - _subscriberServiceHelper.CreateServiceReference(_service), - _subscriberServiceHelper.DiscoverMessageHandlers(_service).Keys) - .ConfigureAwait(false); + foreach (var subscription in _service.DiscoverMessageHandlers()) + { + await _brokerClient.UnsubscribeAsync(_service, subscription.Key, false).ConfigureAwait(false); + } } catch (Exception ex) { diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs index d1b51cf..da0656e 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs @@ -13,7 +13,7 @@ namespace ServiceFabric.PubSubActors.SubscriberServices { - public class SubscriberStatefulServiceBase : StatefulService, ISubscriberService, ISubscriber + public class SubscriberStatefulServiceBase : StatefulService, ISubscriberService { private readonly IBrokerClient _brokerClient; diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs index 9d86756..0b2406c 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs @@ -16,7 +16,7 @@ namespace ServiceFabric.PubSubActors.SubscriberServices /// Base class for a that serves as a subscriber of messages from the broker. /// Subscribe to message types and define a handler callback by using the . /// - public abstract class SubscriberStatelessServiceBase : StatelessService, ISubscriberService, ISubscriber + public abstract class SubscriberStatelessServiceBase : StatelessService, ISubscriberService { private readonly IBrokerClient _brokerClient; From d6a9d8cccac35ee2be325cdca635c75e1137b2a9 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Thu, 28 Feb 2019 09:26:34 -0800 Subject: [PATCH 04/11] remove obsolete extension methods --- ServiceFabric.PubSubActors/BrokerService.cs | 8 +- .../BrokerServiceUnordered.cs | 6 +- .../PublisherActorExtensions.cs | 110 ----------- .../PublisherServiceExtensions.cs | 99 ---------- .../State/PartitionInfoExtensions.cs | 17 -- .../SubscriberActorExtensions.cs | 67 ------- .../LongRunningTaskSubscriber.cs | 18 +- .../SubscriberServiceExtensions.cs | 182 ------------------ 8 files changed, 16 insertions(+), 491 deletions(-) delete mode 100644 ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs delete mode 100644 ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs delete mode 100644 ServiceFabric.PubSubActors/State/PartitionInfoExtensions.cs delete mode 100644 ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs delete mode 100644 ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs diff --git a/ServiceFabric.PubSubActors/BrokerService.cs b/ServiceFabric.PubSubActors/BrokerService.cs index 0e13841..ad94b7e 100644 --- a/ServiceFabric.PubSubActors/BrokerService.cs +++ b/ServiceFabric.PubSubActors/BrokerService.cs @@ -7,15 +7,15 @@ using System.Fabric; using System.Threading.Tasks; using System.Threading; -using ServiceFabric.PubSubActors.PublisherActors; +using ServiceFabric.PubSubActors.Helpers; using ServiceFabric.PubSubActors.SubscriberServices; namespace ServiceFabric.PubSubActors { /// - /// Base class for a that serves as a Broker that accepts messages - /// from Actors & Services calling - /// and forwards them to Actors and Services with strict ordering, so less performant than . + /// Base class for a that serves as a Broker that accepts messages + /// from Actors & Services calling + /// and forwards them to Actors and Services with strict ordering, so less performant than . /// Every message type is mapped to one of the partitions of this service. /// public abstract class BrokerService : BrokerServiceBase diff --git a/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs b/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs index 9e94c8e..81ffc57 100644 --- a/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs +++ b/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs @@ -5,16 +5,16 @@ using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Services.Runtime; +using ServiceFabric.PubSubActors.Helpers; using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.PublisherActors; using ServiceFabric.PubSubActors.State; using ServiceFabric.PubSubActors.SubscriberServices; namespace ServiceFabric.PubSubActors { /// - /// Base class for a that serves as a Broker that accepts messages - /// from Actors & Services calling + /// Base class for a that serves as a Broker that accepts messages + /// from Actors & Services calling /// and forwards them to Actors and Services without strict ordering, so more performant than . /// Every message type is mapped to one of the partitions of this service. /// diff --git a/ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs b/ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs deleted file mode 100644 index 62a55c1..0000000 --- a/ServiceFabric.PubSubActors/PublisherActors/PublisherActorExtensions.cs +++ /dev/null @@ -1,110 +0,0 @@ -using Microsoft.ServiceFabric.Actors.Runtime; -using Microsoft.ServiceFabric.Services.Client; -using Microsoft.ServiceFabric.Services.Remoting.Client; -using ServiceFabric.PubSubActors.Interfaces; -using System; -using System.Fabric; -using System.Fabric.Query; -using System.Threading.Tasks; -using ServiceFabric.PubSubActors.State; - -namespace ServiceFabric.PubSubActors.PublisherActors -{ - /// - /// Common operations of - /// - public static class PublisherActorExtensions - { - /////broker service code - private static ServicePartitionList _cachedPartitions; - - /// - /// Publish a message. - /// - /// - /// - /// The name of the SF Service of type . - /// - [Obsolete("Use ServiceFabric.PubSubActors.Helpers.PublisherActorHelper for testability")] - public static async Task PublishMessageToBrokerServiceAsync(this ActorBase actor, object message, Uri brokerServiceName = null) - { - if (actor == null) throw new ArgumentNullException(nameof(actor)); - if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServices.PublisherServiceExtensions.DiscoverBrokerServiceNameAsync(new Uri(actor.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - - - var wrapper = message.CreateMessageWrapper(); - var brokerService = await GetBrokerServiceForMessageAsync(message, brokerServiceName); - await brokerService.PublishMessageAsync(wrapper); - } - - /// - /// Resolves the to send the message to, based on message type. - /// - /// The message to publish - /// - /// - public static async Task GetPartitionForMessageAsync(object message, Uri brokerServiceName, IHashingHelper hashingHelper = null) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) throw new ArgumentNullException(nameof(brokerServiceName)); - if (hashingHelper == null) hashingHelper = new HashingHelper(); - - string messageTypeName = message.GetType().FullName; - - if (_cachedPartitions == null) - { - var fabricClient = new FabricClient(); - _cachedPartitions = await fabricClient.QueryManager.GetPartitionListAsync(brokerServiceName); - } - int hashCode; - unchecked - { - hashCode = (int)hashingHelper.HashString(messageTypeName); - } - int index = Math.Abs(hashCode % _cachedPartitions.Count); - var partition = _cachedPartitions[index]; - if (partition.PartitionInformation.Kind != ServicePartitionKind.Int64Range) - { - throw new InvalidOperationException("Sorry, only Int64 Range Partitions are supported."); - } - - var info = (Int64RangePartitionInformation)partition.PartitionInformation; - var resolvedPartition = new ServicePartitionKey(info.LowKey); - - return resolvedPartition; - } - - /// - /// Gets the instance for the provided - /// - /// - /// Uri of BrokerService instance - /// - public static Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName) - { - return GetBrokerServiceForMessageAsync(message.GetType().FullName, brokerServiceName); - } - - /// - /// Gets the instance for the provided - /// - /// Full type name of message object. - /// Uri of BrokerService instance - /// - public static async Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName) - { - - var resolvedPartition = await GetPartitionForMessageAsync(messageTypeName, brokerServiceName); - var brokerService = ServiceProxy.Create(brokerServiceName, resolvedPartition, listenerName: BrokerServiceBase.ListenerName); - return brokerService; - } - } -} diff --git a/ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs b/ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs deleted file mode 100644 index d0c47dc..0000000 --- a/ServiceFabric.PubSubActors/PublisherServices/PublisherServiceExtensions.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.PublisherActors; - -namespace ServiceFabric.PubSubActors.PublisherServices -{ - public static class PublisherServiceExtensions - { - /// - /// Publish a message. - /// - /// - /// - /// The name of a SF Service of type . - /// - [Obsolete("Use ServiceFabric.PubSubActors.Helpers.PublisherServiceHelper for testability")] - public static async Task PublishMessageToBrokerServiceAsync(this StatelessService service, object message, - Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) - { - brokerServiceName = - await - DiscoverBrokerServiceNameAsync( - new Uri(service.Context.CodePackageActivationContext.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException( - "No brokerServiceName was provided or discovered in the current application."); - } - } - - var brokerService = - await PublisherActorExtensions.GetBrokerServiceForMessageAsync(message, brokerServiceName); - var wrapper = message.CreateMessageWrapper(); - await brokerService.PublishMessageAsync(wrapper); - } - - /// - /// Publish a message. - /// - /// - /// - /// The name of a SF Service of type . - /// - [Obsolete("Use ServiceFabric.PubSubActors.Helpers.PublisherServiceHelper for testability")] - public static async Task PublishMessageToBrokerServiceAsync(this StatefulServiceBase service, object message, - Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) - { - brokerServiceName = - await - DiscoverBrokerServiceNameAsync( - new Uri(service.Context.CodePackageActivationContext.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException( - "No brokerServiceName was provided or discovered in the current application."); - } - } - - var brokerService = - await PublisherActorExtensions.GetBrokerServiceForMessageAsync(message, brokerServiceName); - var wrapper = message.CreateMessageWrapper(); - await brokerService.PublishMessageAsync(wrapper); - } - - /// - /// Attempts to discover the running in this Application. - /// - /// - /// - [Obsolete("Use ServiceFabric.PubSubActors.Helpers.BrokerServiceLocator for testability")] - - public static async Task DiscoverBrokerServiceNameAsync(Uri applicationName) - { - try - { - var fc = new System.Fabric.FabricClient(); - var property = await fc.PropertyManager.GetPropertyAsync(applicationName, nameof(BrokerService)); - if (property == null) return null; - string value = property.GetValue(); - return new Uri(value); - } - // ReSharper disable once EmptyGeneralCatchClause - catch - { - } - return null; - } - } -} diff --git a/ServiceFabric.PubSubActors/State/PartitionInfoExtensions.cs b/ServiceFabric.PubSubActors/State/PartitionInfoExtensions.cs deleted file mode 100644 index ed71839..0000000 --- a/ServiceFabric.PubSubActors/State/PartitionInfoExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Fabric; - -namespace ServiceFabric.PubSubActors.State -{ - public static class PartitionInfoExtensions - { - public static Int64RangePartitionInformation AsLongPartitionInfo(this ServicePartitionInformation info) - { - return info as Int64RangePartitionInformation; - } - - public static NamedPartitionInformation AsNamedPartitionInfo(this ServicePartitionInformation info) - { - return info as NamedPartitionInformation; - } - } -} \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs b/ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs deleted file mode 100644 index 25caaf1..0000000 --- a/ServiceFabric.PubSubActors/SubscriberActors/SubscriberActorExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Actors.Runtime; -using ServiceFabric.PubSubActors.Interfaces; -using System; -using System.Threading.Tasks; - -namespace ServiceFabric.PubSubActors.SubscriberActors -{ - /// - /// Common operations for Actors to become Subscribers - /// - public static class SubscriberActorExtensions - { - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - [Obsolete("Use ServiceFabric.PubSubActors.Helpers.SubscriberActorHelper for testability")] - public static async Task RegisterMessageTypeWithBrokerServiceAsync(this ActorBase actor, Type messageType, Uri brokerServiceName = null, string routingKey = null) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (actor == null) throw new ArgumentNullException(nameof(actor)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServices.PublisherServiceExtensions.DiscoverBrokerServiceNameAsync(new Uri(actor.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await PublisherActors.PublisherActorExtensions.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - await brokerService.RegisterSubscriberAsync(ActorReference.Get(actor), messageType.FullName, routingKey); - } - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - [Obsolete("Use ServiceFabric.PubSubActors.Helpers.SubscriberActorHelper for testability")] - public static async Task UnregisterMessageTypeWithBrokerServiceAsync(this ActorBase actor, Type messageType, bool flushQueue, Uri brokerServiceName = null) - { - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (actor == null) throw new ArgumentNullException(nameof(actor)); - - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServices.PublisherServiceExtensions.DiscoverBrokerServiceNameAsync(new Uri(actor.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await PublisherActors.PublisherActorExtensions.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - await brokerService.UnregisterSubscriberAsync(ActorReference.Get(actor), messageType.FullName, flushQueue); - } - - /// - /// Deserializes the provided Payload into an intance of type - /// - /// - /// - public static TResult Deserialize(this ActorBase actor, MessageWrapper messageWrapper) - { - return messageWrapper.CreateMessage(); - } - } -} diff --git a/ServiceFabric.PubSubActors/SubscriberServices/LongRunningTaskSubscriber.cs b/ServiceFabric.PubSubActors/SubscriberServices/LongRunningTaskSubscriber.cs index ade8839..1a03e8f 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/LongRunningTaskSubscriber.cs +++ b/ServiceFabric.PubSubActors/SubscriberServices/LongRunningTaskSubscriber.cs @@ -80,7 +80,7 @@ protected override async Task RunAsync(CancellationToken cancellationToken) //peek task description var taskDescriptionMessage = await TimeoutRetryHelper - .ExecuteInTransaction(StateManager, + .ExecuteInTransaction(StateManager, (tran, token, state) => queue.TryPeekAsync(tran, TimeSpan.FromSeconds(4), token), cancellationToken: cancellationToken) .ConfigureAwait(false); if (!taskDescriptionMessage.HasValue) @@ -89,7 +89,7 @@ protected override async Task RunAsync(CancellationToken cancellationToken) } //deserialize task description, create task implementation - var description = this.Deserialize(taskDescriptionMessage.Value); + var description = taskDescriptionMessage.Value.CreateMessage(); var implementation = TaskDescription.ToTaskImplementation(_typeLocator, description); if (implementation == null) { @@ -104,7 +104,7 @@ protected override async Task RunAsync(CancellationToken cancellationToken) await implementation.ExecuteAsync().ConfigureAwait(false); var taskDescriptionMessageDequeued = await TimeoutRetryHelper - .ExecuteInTransaction(StateManager, + .ExecuteInTransaction(StateManager, (tran, token, state) => queue.TryDequeueAsync(tran, TimeSpan.FromSeconds(4), token), cancellationToken: cancellationToken) .ConfigureAwait(false); @@ -147,9 +147,9 @@ protected override async Task RunAsync(CancellationToken cancellationToken) public async Task ReceiveMessageAsync(MessageWrapper message) { //assume that message contains 'TaskDescription' - var description = this.Deserialize(message); + var description = message.CreateMessage(); if (description == null) return; //wrong message - + var queue = await TimeoutRetryHelper.Execute((token, state) => StateManager.GetOrAddAsync>(_queueName)); await TimeoutRetryHelper .ExecuteInTransaction(StateManager, (tran, token, state) => queue.EnqueueAsync(tran, message)) @@ -201,15 +201,15 @@ public interface ITypeLocator } /// - /// Helper class that maps type name to type for . + /// Helper class that maps type name to type for . /// public class TypeLocator : ITypeLocator { private readonly Dictionary _registeredTaskTypes = new Dictionary(); /// - /// Creates a new instance that scans the provided for concrete - /// implementations of type . + /// Creates a new instance that scans the provided for concrete + /// implementations of type . /// /// public TypeLocator(Assembly taskAssembly) @@ -243,7 +243,7 @@ public ITaskImplementation LocateAndCreate(TaskDescription taskDescription) public interface ITaskImplementation { /// - /// Executes the task. + /// Executes the task. /// /// Task ExecuteAsync(); diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs b/ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs deleted file mode 100644 index e83f31b..0000000 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberServiceExtensions.cs +++ /dev/null @@ -1,182 +0,0 @@ -using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Interfaces; -using System; -using System.Fabric; -using System.Reflection; -using System.Threading.Tasks; - -namespace ServiceFabric.PubSubActors.SubscriberServices -{ - public static class SubscriberServiceExtensions - { - /// - /// Deserializes the provided Payload into an instance of type - /// - /// - /// - public static TResult Deserialize(this StatefulServiceBase service, MessageWrapper messageWrapper) - { - if (messageWrapper == null) throw new ArgumentNullException(nameof(messageWrapper)); - if (string.IsNullOrWhiteSpace(messageWrapper.Payload)) throw new ArgumentNullException(nameof(messageWrapper.Payload)); - - var payload = messageWrapper.CreateMessage(); - return payload; - } - - /// - /// Deserializes the provided Payload into an instance of type - /// - /// - /// - public static TResult Deserialize(this StatelessService service, MessageWrapper messageWrapper) - { - if (messageWrapper == null) throw new ArgumentNullException(nameof(messageWrapper)); - if (string.IsNullOrWhiteSpace(messageWrapper.Payload)) throw new ArgumentNullException(nameof(messageWrapper.Payload)); - - var payload = messageWrapper.CreateMessage(); - return payload; - } - - /// - /// Registers this Service as a subscriber for messages of type with the . - /// - /// - public static async Task RegisterMessageTypeWithBrokerServiceAsync(this StatelessService service, Type messageType, Uri brokerServiceName = null, string listenerName = null, string routingKey = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServices.PublisherServiceExtensions.DiscoverBrokerServiceNameAsync(new Uri(service.Context.CodePackageActivationContext.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await PublisherActors.PublisherActorExtensions.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - var serviceReference = CreateServiceReference(service.Context, service.GetServicePartition().PartitionInfo, listenerName); - await brokerService.RegisterServiceSubscriberAsync(serviceReference, messageType.FullName, routingKey); - } - - /// - /// Unregisters this Service as a subscriber for messages of type with the . - /// - /// - public static async Task UnregisterMessageTypeWithBrokerServiceAsync(this StatelessService service, Type messageType, bool flushQueue, Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServices.PublisherServiceExtensions.DiscoverBrokerServiceNameAsync(new Uri(service.Context.CodePackageActivationContext.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await PublisherActors.PublisherActorExtensions.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - var serviceReference = CreateServiceReference(service.Context, service.GetServicePartition().PartitionInfo); - await brokerService.UnregisterServiceSubscriberAsync(serviceReference, messageType.FullName, flushQueue); - } - - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - public static async Task RegisterMessageTypeWithBrokerServiceAsync(this StatefulService service, Type messageType, Uri brokerServiceName = null, string listenerName = null, string routingKey = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServices.PublisherServiceExtensions.DiscoverBrokerServiceNameAsync(new Uri(service.Context.CodePackageActivationContext.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await PublisherActors.PublisherActorExtensions.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - var serviceReference = CreateServiceReference(service.Context, service.GetServicePartition().PartitionInfo, listenerName); - await brokerService.RegisterServiceSubscriberAsync(serviceReference, messageType.FullName, routingKey); - } - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - public static async Task UnregisterMessageTypeWithBrokerServiceAsync(this StatefulService service, Type messageType, bool flushQueue, Uri brokerServiceName = null) - { - if (service == null) throw new ArgumentNullException(nameof(service)); - if (messageType == null) throw new ArgumentNullException(nameof(messageType)); - if (brokerServiceName == null) - { - brokerServiceName = await PublisherServices.PublisherServiceExtensions.DiscoverBrokerServiceNameAsync(new Uri(service.Context.CodePackageActivationContext.ApplicationName)); - if (brokerServiceName == null) - { - throw new InvalidOperationException("No brokerServiceName was provided or discovered in the current application."); - } - } - var brokerService = await PublisherActors.PublisherActorExtensions.GetBrokerServiceForMessageAsync(messageType.Name, brokerServiceName); - var serviceReference = CreateServiceReference(service.Context, service.GetServicePartition().PartitionInfo); - await brokerService.UnregisterServiceSubscriberAsync(serviceReference, messageType.FullName, flushQueue); - } - - /// - /// Gets the Partition info for the provided StatefulServiceBase instance. - /// - /// - /// - private static IStatefulServicePartition GetServicePartition(this StatefulServiceBase serviceBase) - { - if (serviceBase == null) throw new ArgumentNullException(nameof(serviceBase)); - return (IStatefulServicePartition)serviceBase - .GetType() - .GetProperty("Partition", BindingFlags.Instance | BindingFlags.NonPublic) - .GetValue(serviceBase); - } - - /// - /// Gets the Partition info for the provided StatelessService instance. - /// - /// - /// - private static IStatelessServicePartition GetServicePartition(this StatelessService serviceBase) - { - if (serviceBase == null) throw new ArgumentNullException(nameof(serviceBase)); - return (IStatelessServicePartition)serviceBase - .GetType() - .GetProperty("Partition", BindingFlags.Instance | BindingFlags.NonPublic) - .GetValue(serviceBase); - } - - /// - /// Creates a for the provided service context and partition info. - /// - /// - /// - /// (optional) The name of the listener that is used to communicate with the service - /// - public static ServiceReference CreateServiceReference(ServiceContext context, ServicePartitionInformation info, string listenerName = null) - { - var serviceReference = new ServiceReference - { - ApplicationName = context.CodePackageActivationContext.ApplicationName, - PartitionKind = info.Kind, - ServiceUri = context.ServiceName, - PartitionGuid = context.PartitionId, - ListenerName = listenerName - }; - - if (info is Int64RangePartitionInformation longInfo) - { - serviceReference.PartitionKey = longInfo.LowKey; - } - else if (info is NamedPartitionInformation stringInfo) - { - serviceReference.PartitionName = stringInfo.Name; - } - - return serviceReference; - } - } -} From bc7925a0d35c3ab11312e707811574a39a5de076 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Thu, 28 Feb 2019 11:31:46 -0800 Subject: [PATCH 05/11] remove Interfaces project, moved a couple things to different namespace --- README.md | 55 +++++++------ .../Properties/AssemblyInfo.cs | 22 ------ ...rviceFabric.PubSubActors.Interfaces.csproj | 40 ---------- .../GivenServiceReference.cs | 1 - ...GivenSubscriberStatefulServiceBaseTests.cs | 4 +- ...ivenSubscriberStatelessServiceBaseTests.cs | 4 +- .../MockBrokerServiceLocator.cs | 5 +- .../ServiceFabric.PubSubActors.Tests.csproj | 1 - ServiceFabric.PubSubActors.sln | 10 --- ServiceFabric.PubSubActors/BrokerService.cs | 3 +- .../BrokerServiceBase.cs | 3 +- .../BrokerServiceUnordered.cs | 3 +- .../Helpers/BrokerClient.cs | 1 - .../Helpers}/DefaultPayloadSerializer.cs | 3 +- .../Helpers/IBrokerClient.cs | 2 +- .../{ => Helpers}/TimeoutRetryHelper.cs | 2 +- ServiceFabric.PubSubActors/IBrokerService.cs | 6 +- .../ServiceFabric.PubSubActors.csproj | 3 - .../State/ActorReferenceWrapper.cs | 18 ++--- .../State}/MessageWrapper.cs | 13 ++-- .../State/ReferenceWrapper.cs | 6 +- .../State}/ServiceReference.cs | 2 +- .../State/ServiceReferenceWrapper.cs | 77 ++++++------------- .../Subscriber}/ISubscriberActor.cs | 5 +- .../ISubscriberService.cs | 6 +- .../LongRunningTaskSubscriber.cs | 5 +- .../StatefulSubscriberServiceBootstrapper.cs | 8 +- .../StatelessSubscriberServiceBootstrapper.cs | 2 +- .../SubscriberExtensions.cs | 4 +- .../SubscriberStatefulServiceBase.cs | 4 +- .../SubscriberStatelessServiceBase.cs | 12 +-- 31 files changed, 114 insertions(+), 216 deletions(-) delete mode 100644 ServiceFabric.PubSubActors.Interfaces/Properties/AssemblyInfo.cs delete mode 100644 ServiceFabric.PubSubActors.Interfaces/ServiceFabric.PubSubActors.Interfaces.csproj rename {ServiceFabric.PubSubActors.Interfaces => ServiceFabric.PubSubActors/Helpers}/DefaultPayloadSerializer.cs (95%) rename ServiceFabric.PubSubActors/{ => Helpers}/TimeoutRetryHelper.cs (99%) rename {ServiceFabric.PubSubActors.Interfaces => ServiceFabric.PubSubActors/State}/MessageWrapper.cs (92%) rename {ServiceFabric.PubSubActors.Interfaces => ServiceFabric.PubSubActors/State}/ServiceReference.cs (97%) rename {ServiceFabric.PubSubActors.Interfaces => ServiceFabric.PubSubActors/Subscriber}/ISubscriberActor.cs (80%) rename ServiceFabric.PubSubActors/{SubscriberServices => Subscriber}/ISubscriberService.cs (71%) rename ServiceFabric.PubSubActors/{SubscriberServices => Subscriber}/LongRunningTaskSubscriber.cs (98%) rename ServiceFabric.PubSubActors/{SubscriberServices => Subscriber}/StatefulSubscriberServiceBootstrapper.cs (98%) rename ServiceFabric.PubSubActors/{SubscriberServices => Subscriber}/StatelessSubscriberServiceBootstrapper.cs (99%) rename ServiceFabric.PubSubActors/{Helpers => Subscriber}/SubscriberExtensions.cs (92%) rename ServiceFabric.PubSubActors/{SubscriberServices => Subscriber}/SubscriberStatefulServiceBase.cs (97%) rename ServiceFabric.PubSubActors/{SubscriberServices => Subscriber}/SubscriberStatelessServiceBase.cs (97%) diff --git a/README.md b/README.md index 51254f3..c457dc1 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Please also make sure all feature additions have a corresponding unit test. ## Nuget: https://www.nuget.org/packages/ServiceFabric.PubSubActors -https://www.nuget.org/packages/ServiceFabric.PubSubActors.Interfaces (for Actor interfaces) +https://www.nuget.org/packages/ServiceFabric.PubSubActors.Interfaces (obsolete as of v8.0) ## Getting started @@ -68,7 +68,6 @@ https://www.nuget.org/packages/ServiceFabric.PubSubActors.Interfaces (for Actor Using this package you can reliably send messages from Publishers (Actors/Services) to many Subscribers (Actors/Services). This is done using an intermediate, which is the BrokerService. Add this package to all Reliable Actor & Service projects that participate in the pub/sub messaging. -Add the package 'ServiceFabric.PubSubActors.Interfaces' to all (*ReliableActor).Interfaces projects. | publisher | broker |subscriber| @@ -88,7 +87,6 @@ Add the package 'ServiceFabric.PubSubActors.Interfaces' to all (*ReliableActor). Add a new Stateful Reliable Service project. Call it 'PubSubService' (optional). Add Nuget package 'ServiceFabric.PubSubActors' to the 'PubSubActor' project -Add Nuget package 'ServiceFabric.PubSubActors.Interfaces' to the project. Replace the code of PubSubService with the following code: ```csharp internal sealed class PubSubService : BrokerService @@ -135,31 +133,45 @@ In this example, the Actor called 'SubscribingActor' subscribes to messages of T Add a Reliable Stateless Actor project called 'SubscribingActor'. Add Nuget package 'ServiceFabric.PubSubActors' to the 'SubscribingActor' project -Add Nuget package 'ServiceFabric.PubSubActors.Interfaces' to the 'SubscribingActor.Interfaces' project. Add a project reference to the shared data contracts library ('DataContracts'). -Go to the SubscribingActor.Interfaces project, open the file 'ISubscribingActor' and replace the contents with this code: -**notice this implements ISubscriberActor from the package 'ServiceFabric.PubSubActors.Interfaces' which adds a Receive method. The additional methods are to enable this actor to be manipulated from the outside.** +Open the file 'SubscribingActor.cs' and replace the contents with the code below. +**notice that this Actor now implements 'ISubscriberActor' indirectly.** ```csharp -public interface ISubscribingActor : ISubscriberActor +[ActorService(Name = nameof(SubscribingActor))] +[StatePersistence(StatePersistence.None)] +internal class SubscribingActor : Actor, ISubscriberActor +{ + private readonly IBrokerClient _brokerClient; + + public SubscribingActor(ActorService actorService, ActorId actorId, IBrokerClient brokerClient) + : base(actorService, actorId) { - // allow external callers to manipulate register/unregister on this sample actor: - //for regular messaging: - Task RegisterAsync(); - Task UnregisterAsync(); - //for relayed messaging: - Task RegisterWithRelayAsync(); - Task UnregisterWithRelayAsync(); - //for service broker messaging: - Task RegisterWithBrokerServiceAsync(); - Task UnregisterWithBrokerServiceAsync(); + _brokerClient = brokerClient ?? new BrokerClient(); } -``` -Open the file 'SubscribingActor.cs' and replace the contents with the code below. -**notice that this Actor now implements 'ISubscriberActor' indirectly.** -https://github.com/loekd/ServiceFabric.PubSubActors/blob/master/ServiceFabric.PubSubActors.Demo/SubscribingActor/SubscribingActor.cs + protected override async Task OnActivateAsync() + { + await _brokerClient.SubscribeAsync(this, typeof(PublishedMessageOne), HandleMessageOne); + } + + protected override async Task OnDeactivateAsync() + { + await _brokerClient.UnsubscribeAsync(this, typeof(PublishedMessageOne), true); + } + + public Task ReceiveMessageAsync(MessageWrapper message) + { + return _brokerClient.ProcessMessageAsync(message); + } + private Task HandleMessageOne(PublishedMessageOne message) + { + ActorEventSource.Current.ActorMessage(this, $"Received message: {message.Content}"); + return Task.CompletedTask; + } +} +``` ### Subscribing to messages using Services using our base class @@ -168,7 +180,6 @@ In this example, the Service called 'SubscribingStatelessService' subscribes to Add a Reliable Stateless Service project called 'SubscribingStatelessService'. Add Nuget package 'ServiceFabric.PubSubActors'. -Add Nuget package 'ServiceFabric.PubSubActors.Interfaces'. Add a project reference to the shared data contracts library ('DataContracts'). Now open the file SubscribingStatelessService.cs in the project 'SubscribingStatelessService' and replace the SubscribingStatelessService class with this code: diff --git a/ServiceFabric.PubSubActors.Interfaces/Properties/AssemblyInfo.cs b/ServiceFabric.PubSubActors.Interfaces/Properties/AssemblyInfo.cs deleted file mode 100644 index d559b2b..0000000 --- a/ServiceFabric.PubSubActors.Interfaces/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ServiceFabric.PubSubActors.Interfaces")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ServiceFabric.PubSubActors.Interfaces")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("8e319be1-af0a-4683-997f-7577e369850a")] diff --git a/ServiceFabric.PubSubActors.Interfaces/ServiceFabric.PubSubActors.Interfaces.csproj b/ServiceFabric.PubSubActors.Interfaces/ServiceFabric.PubSubActors.Interfaces.csproj deleted file mode 100644 index f6b1abd..0000000 --- a/ServiceFabric.PubSubActors.Interfaces/ServiceFabric.PubSubActors.Interfaces.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - 2019 - ServiceFabric.PubSubActors.Interfaces - Loek Duys - net452;net46;netstandard2.0 - x64 - x64 - 7.6.2 - ServiceFabric.PubSubActors.Interfaces - ServiceFabric.PubSubActors.Interfaces - ServiceFabric;Service;Fabric;Actor;Pub;Sub;Reliable - https://github.com/loekd/ServiceFabric.PubSubActors - https://github.com/loekd/ServiceFabric.PubSubActors/blob/master/LICENSE.md - true - git - https://github.com/loekd/ServiceFabric.PubSubActors.git - false - false - false - false - false - false - true - true - true - - - true - False - true - ..\ServiceFabric.PubSubActors.snk - - - - - - - - \ No newline at end of file diff --git a/ServiceFabric.PubSubActors.Tests/GivenServiceReference.cs b/ServiceFabric.PubSubActors.Tests/GivenServiceReference.cs index 1ba395c..afd8da7 100644 --- a/ServiceFabric.PubSubActors.Tests/GivenServiceReference.cs +++ b/ServiceFabric.PubSubActors.Tests/GivenServiceReference.cs @@ -1,6 +1,5 @@ using Microsoft.ServiceFabric.Actors; using Microsoft.VisualStudio.TestTools.UnitTesting; -using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.State; namespace ServiceFabric.PubSubActors.Tests diff --git a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs index 4c79bca..b1207f9 100644 --- a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs +++ b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatefulServiceBaseTests.cs @@ -4,8 +4,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using ServiceFabric.Mocks; using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.SubscriberServices; +using ServiceFabric.PubSubActors.State; +using ServiceFabric.PubSubActors.Subscriber; namespace ServiceFabric.PubSubActors.Tests { diff --git a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs index 408462e..9ae212a 100644 --- a/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs +++ b/ServiceFabric.PubSubActors.Tests/GivenSubscriberStatelessServiceBaseTests.cs @@ -4,8 +4,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using ServiceFabric.Mocks; using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.SubscriberServices; +using ServiceFabric.PubSubActors.State; +using ServiceFabric.PubSubActors.Subscriber; namespace ServiceFabric.PubSubActors.Tests { diff --git a/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs b/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs index 2357eef..7770614 100644 --- a/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs +++ b/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs @@ -3,7 +3,6 @@ using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Services.Client; using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.State; namespace ServiceFabric.PubSubActors.Tests @@ -43,7 +42,7 @@ public Task GetBrokerServiceForMessageAsync(string messageTypeNa public class MockBrokerService : IBrokerService { - public Task RegisterSubscriberAsync(ActorReference actor, string messageTypeName) + public Task RegisterSubscriberAsync(ActorReference actor, string messageTypeName, string routingKey = null) { return Task.CompletedTask; } @@ -53,7 +52,7 @@ public Task UnregisterSubscriberAsync(ActorReference actor, string messageTypeNa return Task.CompletedTask; } - public Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName) + public Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, string routingKey = null) { return Task.CompletedTask; } diff --git a/ServiceFabric.PubSubActors.Tests/ServiceFabric.PubSubActors.Tests.csproj b/ServiceFabric.PubSubActors.Tests/ServiceFabric.PubSubActors.Tests.csproj index 42fe90b..5b29087 100644 --- a/ServiceFabric.PubSubActors.Tests/ServiceFabric.PubSubActors.Tests.csproj +++ b/ServiceFabric.PubSubActors.Tests/ServiceFabric.PubSubActors.Tests.csproj @@ -10,7 +10,6 @@ - \ No newline at end of file diff --git a/ServiceFabric.PubSubActors.sln b/ServiceFabric.PubSubActors.sln index 16d88dd..9bf10e4 100644 --- a/ServiceFabric.PubSubActors.sln +++ b/ServiceFabric.PubSubActors.sln @@ -12,8 +12,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceFabric.PubSubActors", "ServiceFabric.PubSubActors\ServiceFabric.PubSubActors.csproj", "{266D0C63-57EE-4C0D-873F-B3235B062CF4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceFabric.PubSubActors.Interfaces", "ServiceFabric.PubSubActors.Interfaces\ServiceFabric.PubSubActors.Interfaces.csproj", "{8E319BE1-AF0A-4683-997F-7577E369850A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceFabric.PubSubActors.Tests", "ServiceFabric.PubSubActors.Tests\ServiceFabric.PubSubActors.Tests.csproj", "{29169DCB-AA96-4B25-8395-32DC00473F34}" EndProject Global @@ -32,14 +30,6 @@ Global {266D0C63-57EE-4C0D-873F-B3235B062CF4}.Release|Any CPU.Build.0 = Release|Any CPU {266D0C63-57EE-4C0D-873F-B3235B062CF4}.Release|x64.ActiveCfg = Release|Any CPU {266D0C63-57EE-4C0D-873F-B3235B062CF4}.Release|x64.Build.0 = Release|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Debug|x64.ActiveCfg = Debug|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Debug|x64.Build.0 = Debug|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Release|Any CPU.Build.0 = Release|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Release|x64.ActiveCfg = Release|Any CPU - {8E319BE1-AF0A-4683-997F-7577E369850A}.Release|x64.Build.0 = Release|Any CPU {29169DCB-AA96-4B25-8395-32DC00473F34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29169DCB-AA96-4B25-8395-32DC00473F34}.Debug|Any CPU.Build.0 = Debug|Any CPU {29169DCB-AA96-4B25-8395-32DC00473F34}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/ServiceFabric.PubSubActors/BrokerService.cs b/ServiceFabric.PubSubActors/BrokerService.cs index ad94b7e..3396be8 100644 --- a/ServiceFabric.PubSubActors/BrokerService.cs +++ b/ServiceFabric.PubSubActors/BrokerService.cs @@ -1,14 +1,13 @@ using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.State; using System; using System.Fabric; using System.Threading.Tasks; using System.Threading; using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.SubscriberServices; +using ServiceFabric.PubSubActors.Subscriber; namespace ServiceFabric.PubSubActors { diff --git a/ServiceFabric.PubSubActors/BrokerServiceBase.cs b/ServiceFabric.PubSubActors/BrokerServiceBase.cs index 1ee4913..17357ed 100644 --- a/ServiceFabric.PubSubActors/BrokerServiceBase.cs +++ b/ServiceFabric.PubSubActors/BrokerServiceBase.cs @@ -12,9 +12,8 @@ using Microsoft.ServiceFabric.Services.Communication.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.State; -using ServiceFabric.PubSubActors.SubscriberServices; +using ServiceFabric.PubSubActors.Subscriber; namespace ServiceFabric.PubSubActors { diff --git a/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs b/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs index 81ffc57..4d488e1 100644 --- a/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs +++ b/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs @@ -6,9 +6,8 @@ using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.State; -using ServiceFabric.PubSubActors.SubscriberServices; +using ServiceFabric.PubSubActors.Subscriber; namespace ServiceFabric.PubSubActors { diff --git a/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs index 16b9e65..e63ae59 100644 --- a/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs +++ b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs @@ -6,7 +6,6 @@ using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Actors.Runtime; using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.State; namespace ServiceFabric.PubSubActors.Helpers diff --git a/ServiceFabric.PubSubActors.Interfaces/DefaultPayloadSerializer.cs b/ServiceFabric.PubSubActors/Helpers/DefaultPayloadSerializer.cs similarity index 95% rename from ServiceFabric.PubSubActors.Interfaces/DefaultPayloadSerializer.cs rename to ServiceFabric.PubSubActors/Helpers/DefaultPayloadSerializer.cs index 17c58cb..0f0efd2 100644 --- a/ServiceFabric.PubSubActors.Interfaces/DefaultPayloadSerializer.cs +++ b/ServiceFabric.PubSubActors/Helpers/DefaultPayloadSerializer.cs @@ -1,7 +1,8 @@ using System; using Newtonsoft.Json; +using ServiceFabric.PubSubActors.State; -namespace ServiceFabric.PubSubActors.Interfaces +namespace ServiceFabric.PubSubActors.Helpers { /// /// The default serializer to use for diff --git a/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs b/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs index d633211..71f05f4 100644 --- a/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs +++ b/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Microsoft.ServiceFabric.Actors.Runtime; using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.State; namespace ServiceFabric.PubSubActors.Helpers { diff --git a/ServiceFabric.PubSubActors/TimeoutRetryHelper.cs b/ServiceFabric.PubSubActors/Helpers/TimeoutRetryHelper.cs similarity index 99% rename from ServiceFabric.PubSubActors/TimeoutRetryHelper.cs rename to ServiceFabric.PubSubActors/Helpers/TimeoutRetryHelper.cs index 6d7845a..f9b737a 100644 --- a/ServiceFabric.PubSubActors/TimeoutRetryHelper.cs +++ b/ServiceFabric.PubSubActors/Helpers/TimeoutRetryHelper.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; -namespace ServiceFabric.PubSubActors +namespace ServiceFabric.PubSubActors.Helpers { /// /// Provides retry support when using the . diff --git a/ServiceFabric.PubSubActors/IBrokerService.cs b/ServiceFabric.PubSubActors/IBrokerService.cs index 4fee362..580d021 100644 --- a/ServiceFabric.PubSubActors/IBrokerService.cs +++ b/ServiceFabric.PubSubActors/IBrokerService.cs @@ -31,7 +31,7 @@ public interface IBrokerService : IService /// The full type name of the message to subscribe to. /// Reference to the Service to register. /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. - Task RegisterServiceSubscriberAsync(Interfaces.ServiceReference service, string messageTypeName, string routingKey); + Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, string routingKey); /// /// Unregisters a service as a subscriber for messages. @@ -39,7 +39,7 @@ public interface IBrokerService : IService /// The full type name of the message to subscribe to. /// Reference to the Service to unregister. /// Publish any remaining messages. - Task UnregisterServiceSubscriberAsync(Interfaces.ServiceReference service, string messageTypeName, bool flushQueue); + Task UnregisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, bool flushQueue); /// /// Registers a Service or Actor as a subscriber for messages. @@ -61,6 +61,6 @@ public interface IBrokerService : IService /// /// The message to publish /// - Task PublishMessageAsync(Interfaces.MessageWrapper message); + Task PublishMessageAsync(MessageWrapper message); } } diff --git a/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj b/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj index be2f3b3..cac6eba 100644 --- a/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj +++ b/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj @@ -36,9 +36,6 @@ true - - - diff --git a/ServiceFabric.PubSubActors/State/ActorReferenceWrapper.cs b/ServiceFabric.PubSubActors/State/ActorReferenceWrapper.cs index 79e711a..8ee070b 100644 --- a/ServiceFabric.PubSubActors/State/ActorReferenceWrapper.cs +++ b/ServiceFabric.PubSubActors/State/ActorReferenceWrapper.cs @@ -1,9 +1,11 @@ using Microsoft.ServiceFabric.Actors; using Newtonsoft.Json.Linq; -using ServiceFabric.PubSubActors.Interfaces; using System; using System.Runtime.Serialization; using System.Threading.Tasks; +using Microsoft.ServiceFabric.Actors; +using ServiceFabric.PubSubActors.Helpers; +using ServiceFabric.PubSubActors.Subscriber; namespace ServiceFabric.PubSubActors.State { @@ -13,11 +15,7 @@ namespace ServiceFabric.PubSubActors.State [DataContract] public class ActorReferenceWrapper : ReferenceWrapper { - - public override string Name - { - get { return $"{ActorReference.ServiceUri}\t{ActorReference.ActorId}"; } - } + public override string Name => $"{ActorReference.ServiceUri}\t{ActorReference.ActorId}"; /// /// Gets the wrapped @@ -73,7 +71,7 @@ public override bool Equals(object obj) } /// - /// Serves as a hash function for a particular type. + /// Serves as a hash function for a particular type. /// /// /// A hash code for the current object. @@ -108,10 +106,10 @@ public override bool Equals(ReferenceWrapper other) /// public override Task PublishAsync(MessageWrapper message) { - if (string.IsNullOrWhiteSpace(RoutingKey) - || ShouldDeliverMessage(message)) + if (string.IsNullOrWhiteSpace(RoutingKey) || ShouldDeliverMessage(message)) { - return MessageWrapperExtensions.PublishAsync(this, message); + var actor = (ISubscriberActor)ActorReference.Bind(typeof(ISubscriberActor)); + return actor.ReceiveMessageAsync(message); } return Task.FromResult(true); diff --git a/ServiceFabric.PubSubActors.Interfaces/MessageWrapper.cs b/ServiceFabric.PubSubActors/State/MessageWrapper.cs similarity index 92% rename from ServiceFabric.PubSubActors.Interfaces/MessageWrapper.cs rename to ServiceFabric.PubSubActors/State/MessageWrapper.cs index 45ca9e7..0a90c51 100644 --- a/ServiceFabric.PubSubActors.Interfaces/MessageWrapper.cs +++ b/ServiceFabric.PubSubActors/State/MessageWrapper.cs @@ -1,11 +1,12 @@ using System; using System.Reflection; using System.Runtime.Serialization; +using ServiceFabric.PubSubActors.Helpers; -namespace ServiceFabric.PubSubActors.Interfaces +namespace ServiceFabric.PubSubActors.State { /// - /// Generic message format. Contains message CLR type (full name) and serialized payload. If you know the Message Type you can deserialize + /// Generic message format. Contains message CLR type (full name) and serialized payload. If you know the Message Type you can deserialize /// the payload into that object. /// [DataContract] @@ -40,7 +41,7 @@ public class MessageWrapper public static class MessageWrapperExtensions { /// - /// Gets or sets the to use when setting the . + /// Gets or sets the to use when setting the . /// Defaults to which uses Json.Net. /// public static IPayloadSerializer PayloadSerializer { get; set; } = new DefaultPayloadSerializer(); @@ -49,7 +50,7 @@ public static class MessageWrapperExtensions /// Convert the provided into a /// /// - /// + /// public static MessageWrapper CreateMessageWrapper(this object message) { var messageType = message.GetType(); @@ -66,7 +67,7 @@ public static MessageWrapper CreateMessageWrapper(this object message) /// Convert the provided into an object of type /// /// - /// + /// public static TResult CreateMessage(this MessageWrapper messageWrapper) { var message = (PayloadSerializer ?? new DefaultPayloadSerializer()).Deserialize(messageWrapper.Payload); @@ -77,7 +78,7 @@ public static TResult CreateMessage(this MessageWrapper messageWrapper) /// Convert the provided into an object of type /// /// - /// + /// public static object CreateMessage(this MessageWrapper messageWrapper) { var type = Type.GetType(messageWrapper.MessageType, false); diff --git a/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs b/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs index a3f5800..d3e6825 100644 --- a/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs +++ b/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs @@ -2,7 +2,7 @@ using System.Runtime.Serialization; using System.Threading.Tasks; using Newtonsoft.Json.Linq; -using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.Helpers; namespace ServiceFabric.PubSubActors.State { @@ -96,12 +96,12 @@ public string GetDeadLetterQueueName() /// public bool ShouldDeliverMessage(MessageWrapper message) { - if (!(Interfaces.MessageWrapperExtensions.PayloadSerializer is DefaultPayloadSerializer)) + if (!(MessageWrapperExtensions.PayloadSerializer is DefaultPayloadSerializer)) return true; if (_routingKeyValue == null) return true; - var token = Interfaces.MessageWrapperExtensions.PayloadSerializer.Deserialize(message.Payload); + var token = MessageWrapperExtensions.PayloadSerializer.Deserialize(message.Payload); string value = (string)token.SelectToken(_routingKeyValue[0]); return string.Equals(_routingKeyValue[1], value, StringComparison.InvariantCultureIgnoreCase); diff --git a/ServiceFabric.PubSubActors.Interfaces/ServiceReference.cs b/ServiceFabric.PubSubActors/State/ServiceReference.cs similarity index 97% rename from ServiceFabric.PubSubActors.Interfaces/ServiceReference.cs rename to ServiceFabric.PubSubActors/State/ServiceReference.cs index 092d2b9..e3229f2 100644 --- a/ServiceFabric.PubSubActors.Interfaces/ServiceReference.cs +++ b/ServiceFabric.PubSubActors/State/ServiceReference.cs @@ -2,7 +2,7 @@ using System.Fabric; using System.Runtime.Serialization; -namespace ServiceFabric.PubSubActors.Interfaces +namespace ServiceFabric.PubSubActors.State { [DataContract] public class ServiceReference diff --git a/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs b/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs index a819db9..89c3aff 100644 --- a/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs +++ b/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs @@ -1,7 +1,6 @@ using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; -using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.SubscriberServices; +using ServiceFabric.PubSubActors.Subscriber; using System; using System.Fabric; using System.Runtime.Serialization; @@ -15,10 +14,9 @@ namespace ServiceFabric.PubSubActors.State [DataContract] public class ServiceReferenceWrapper : ReferenceWrapper { - public override string Name - { - get { return ServiceReference.Description; } - } + private static readonly Lazy ServiceProxyFactoryLazy = new Lazy(()=> new ServiceProxyFactory()); + + public override string Name => ServiceReference.Description; /// /// Gets the wrapped @@ -70,7 +68,7 @@ public override bool Equals(object obj) } /// - /// Serves as a hash function for a particular type. + /// Serves as a hash function for a particular type. /// /// /// A hash code for the current object. @@ -122,57 +120,28 @@ public override bool Equals(ReferenceWrapper other) /// public override Task PublishAsync(MessageWrapper message) { - if (string.IsNullOrWhiteSpace(RoutingKey) - || ShouldDeliverMessage(message)) + if (string.IsNullOrWhiteSpace(RoutingKey) || ShouldDeliverMessage(message)) { - return MessageWrapperExtensions.PublishAsync(this, message); + ServicePartitionKey partitionKey; + switch (ServiceReference.PartitionKind) + { + case ServicePartitionKind.Singleton: + partitionKey = ServicePartitionKey.Singleton; + break; + case ServicePartitionKind.Int64Range: + partitionKey = new ServicePartitionKey(ServiceReference.PartitionKey); + break; + case ServicePartitionKind.Named: + partitionKey = new ServicePartitionKey(ServiceReference.PartitionName); + break; + default: + throw new ArgumentOutOfRangeException(); + } + var client = ServiceProxyFactoryLazy.Value.CreateServiceProxy(ServiceReference.ServiceUri, partitionKey); + return client.ReceiveMessageAsync(message); } return Task.FromResult(true); } } - - internal static class MessageWrapperExtensions - { - private static readonly Lazy ServiceProxyFactoryLazy = new Lazy(() => new ServiceProxyFactory()); - - /// - /// Attempts to publish the message to a listener. - /// - /// - /// - /// - public static Task PublishAsync(this ServiceReferenceWrapper wrapper, MessageWrapper message) - { - ServicePartitionKey partitionKey; - switch (wrapper.ServiceReference.PartitionKind) - { - case ServicePartitionKind.Singleton: - partitionKey = ServicePartitionKey.Singleton; - break; - case ServicePartitionKind.Int64Range: - partitionKey = new ServicePartitionKey(wrapper.ServiceReference.PartitionKey); - break; - case ServicePartitionKind.Named: - partitionKey = new ServicePartitionKey(wrapper.ServiceReference.PartitionName); - break; - default: - throw new ArgumentOutOfRangeException(); - } - var client = ServiceProxyFactoryLazy.Value.CreateServiceProxy(wrapper.ServiceReference.ServiceUri, partitionKey); - return client.ReceiveMessageAsync(message); - } - - /// - /// Attempts to publish the message to a listener. - /// - /// - /// - /// - public static Task PublishAsync(this ActorReferenceWrapper wrapper, MessageWrapper message) - { - ISubscriberActor actor = (ISubscriberActor)wrapper.ActorReference.Bind(typeof(ISubscriberActor)); - return actor.ReceiveMessageAsync(message); - } - } } \ No newline at end of file diff --git a/ServiceFabric.PubSubActors.Interfaces/ISubscriberActor.cs b/ServiceFabric.PubSubActors/Subscriber/ISubscriberActor.cs similarity index 80% rename from ServiceFabric.PubSubActors.Interfaces/ISubscriberActor.cs rename to ServiceFabric.PubSubActors/Subscriber/ISubscriberActor.cs index bdc5001..cfa9b25 100644 --- a/ServiceFabric.PubSubActors.Interfaces/ISubscriberActor.cs +++ b/ServiceFabric.PubSubActors/Subscriber/ISubscriberActor.cs @@ -1,11 +1,12 @@ using System.Threading.Tasks; using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Actors.Runtime; +using ServiceFabric.PubSubActors.State; -namespace ServiceFabric.PubSubActors.Interfaces +namespace ServiceFabric.PubSubActors.Subscriber { /// - /// Defines a common interface for all Subscriber Actors. + /// Defines a common interface for all Subscriber Actors. /// Don't forget to mark implementing classes with /// the attribute like: [ActorService(Name = nameof(ISubscribingActor))] where ISubscribingActor is defined in your own project. /// diff --git a/ServiceFabric.PubSubActors/SubscriberServices/ISubscriberService.cs b/ServiceFabric.PubSubActors/Subscriber/ISubscriberService.cs similarity index 71% rename from ServiceFabric.PubSubActors/SubscriberServices/ISubscriberService.cs rename to ServiceFabric.PubSubActors/Subscriber/ISubscriberService.cs index e228e7c..6423911 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/ISubscriberService.cs +++ b/ServiceFabric.PubSubActors/Subscriber/ISubscriberService.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Remoting; -using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.State; -namespace ServiceFabric.PubSubActors.SubscriberServices +namespace ServiceFabric.PubSubActors.Subscriber { /// - /// Defines a common interface for all Subscriber Services. + /// Defines a common interface for all Subscriber Services. /// public interface ISubscriberService : IService { diff --git a/ServiceFabric.PubSubActors/SubscriberServices/LongRunningTaskSubscriber.cs b/ServiceFabric.PubSubActors/Subscriber/LongRunningTaskSubscriber.cs similarity index 98% rename from ServiceFabric.PubSubActors/SubscriberServices/LongRunningTaskSubscriber.cs rename to ServiceFabric.PubSubActors/Subscriber/LongRunningTaskSubscriber.cs index 1a03e8f..557145e 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/LongRunningTaskSubscriber.cs +++ b/ServiceFabric.PubSubActors/Subscriber/LongRunningTaskSubscriber.cs @@ -11,9 +11,10 @@ using Microsoft.ServiceFabric.Services.Remoting.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using Newtonsoft.Json; -using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.Helpers; +using ServiceFabric.PubSubActors.State; -namespace ServiceFabric.PubSubActors.SubscriberServices +namespace ServiceFabric.PubSubActors.Subscriber { /// /// Base implementation of a that runs long running tasks without delaying . diff --git a/ServiceFabric.PubSubActors/SubscriberServices/StatefulSubscriberServiceBootstrapper.cs b/ServiceFabric.PubSubActors/Subscriber/StatefulSubscriberServiceBootstrapper.cs similarity index 98% rename from ServiceFabric.PubSubActors/SubscriberServices/StatefulSubscriberServiceBootstrapper.cs rename to ServiceFabric.PubSubActors/Subscriber/StatefulSubscriberServiceBootstrapper.cs index f21e9b9..6e4322c 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/StatefulSubscriberServiceBootstrapper.cs +++ b/ServiceFabric.PubSubActors/Subscriber/StatefulSubscriberServiceBootstrapper.cs @@ -1,11 +1,11 @@ -using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Helpers; -using System; +using System; using System.Fabric; using System.Fabric.Description; using System.Threading.Tasks; +using Microsoft.ServiceFabric.Services.Runtime; +using ServiceFabric.PubSubActors.Helpers; -namespace ServiceFabric.PubSubActors.SubscriberServices +namespace ServiceFabric.PubSubActors.Subscriber { /// /// Factory for Stateful subscriber services, automatically registers subscriptions for messages. diff --git a/ServiceFabric.PubSubActors/SubscriberServices/StatelessSubscriberServiceBootstrapper.cs b/ServiceFabric.PubSubActors/Subscriber/StatelessSubscriberServiceBootstrapper.cs similarity index 99% rename from ServiceFabric.PubSubActors/SubscriberServices/StatelessSubscriberServiceBootstrapper.cs rename to ServiceFabric.PubSubActors/Subscriber/StatelessSubscriberServiceBootstrapper.cs index e351141..e396080 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/StatelessSubscriberServiceBootstrapper.cs +++ b/ServiceFabric.PubSubActors/Subscriber/StatelessSubscriberServiceBootstrapper.cs @@ -5,7 +5,7 @@ using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Helpers; -namespace ServiceFabric.PubSubActors.SubscriberServices +namespace ServiceFabric.PubSubActors.Subscriber { /// /// Factory for Stateful subscriber services, automatically registers subscriptions for messages. diff --git a/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs b/ServiceFabric.PubSubActors/Subscriber/SubscriberExtensions.cs similarity index 92% rename from ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs rename to ServiceFabric.PubSubActors/Subscriber/SubscriberExtensions.cs index 49c3a9b..8ca6e38 100644 --- a/ServiceFabric.PubSubActors/Helpers/SubscriberExtensions.cs +++ b/ServiceFabric.PubSubActors/Subscriber/SubscriberExtensions.cs @@ -3,10 +3,8 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; -using ServiceFabric.PubSubActors.Interfaces; -using ServiceFabric.PubSubActors.SubscriberServices; -namespace ServiceFabric.PubSubActors.Helpers +namespace ServiceFabric.PubSubActors.Subscriber { /// /// Marks a service method as being capable of receiving messages. diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatefulServiceBase.cs similarity index 97% rename from ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs rename to ServiceFabric.PubSubActors/Subscriber/SubscriberStatefulServiceBase.cs index da0656e..9e7b778 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatefulServiceBase.cs +++ b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatefulServiceBase.cs @@ -9,9 +9,9 @@ using Microsoft.ServiceFabric.Services.Remoting.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.Interfaces; +using ServiceFabric.PubSubActors.State; -namespace ServiceFabric.PubSubActors.SubscriberServices +namespace ServiceFabric.PubSubActors.Subscriber { public class SubscriberStatefulServiceBase : StatefulService, ISubscriberService { diff --git a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatelessServiceBase.cs similarity index 97% rename from ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs rename to ServiceFabric.PubSubActors/Subscriber/SubscriberStatelessServiceBase.cs index 0b2406c..b380a16 100644 --- a/ServiceFabric.PubSubActors/SubscriberServices/SubscriberStatelessServiceBase.cs +++ b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatelessServiceBase.cs @@ -1,16 +1,16 @@ using System; -using Microsoft.ServiceFabric.Services.Communication.Runtime; -using Microsoft.ServiceFabric.Services.Remoting.Runtime; -using Microsoft.ServiceFabric.Services.Runtime; -using ServiceFabric.PubSubActors.Helpers; -using ServiceFabric.PubSubActors.Interfaces; using System.Collections.Generic; using System.Fabric; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.ServiceFabric.Services.Communication.Runtime; +using Microsoft.ServiceFabric.Services.Remoting.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; +using ServiceFabric.PubSubActors.Helpers; +using ServiceFabric.PubSubActors.State; -namespace ServiceFabric.PubSubActors.SubscriberServices +namespace ServiceFabric.PubSubActors.Subscriber { /// /// Base class for a that serves as a subscriber of messages from the broker. From ab83854be865cf4149d1e474bb2b37ee6a60e77f Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Thu, 28 Feb 2019 13:47:31 -0800 Subject: [PATCH 06/11] remove obsolete code from BrokerService and BrokerServiceLocator --- README.md | 12 +- .../MockBrokerServiceLocator.cs | 32 --- ServiceFabric.PubSubActors/BrokerService.cs | 10 +- .../BrokerServiceBase.cs | 207 ++++++------------ .../BrokerServiceUnordered.cs | 10 +- .../Helpers/BrokerServiceLocator.cs | 83 ++++--- .../Helpers/IBrokerServiceLocator.cs | 16 -- ServiceFabric.PubSubActors/IBrokerService.cs | 32 --- .../State/BrokerServiceState.cs | 5 +- .../State/ReferenceWrapper.cs | 8 - .../State/ServiceReference.cs | 4 - .../State/ServiceReferenceWrapper.cs | 4 +- 12 files changed, 118 insertions(+), 305 deletions(-) diff --git a/README.md b/README.md index c457dc1..71b324e 100644 --- a/README.md +++ b/README.md @@ -94,8 +94,8 @@ internal sealed class PubSubService : BrokerService public PubSubService(StatefulServiceContext context) : base(context) { - //optional: provide a logging callback - ServiceEventSourceMessageCallback = message => ServiceEventSource.Current.ServiceMessage(this, message); + //optional: provide a logging callback + ServiceEventSourceMessageCallback = message => ServiceEventSource.Current.ServiceMessage(this, message); } } ``` @@ -155,11 +155,6 @@ internal class SubscribingActor : Actor, ISubscriberActor await _brokerClient.SubscribeAsync(this, typeof(PublishedMessageOne), HandleMessageOne); } - protected override async Task OnDeactivateAsync() - { - await _brokerClient.UnsubscribeAsync(this, typeof(PublishedMessageOne), true); - } - public Task ReceiveMessageAsync(MessageWrapper message) { return _brokerClient.ProcessMessageAsync(message); @@ -186,7 +181,8 @@ Now open the file SubscribingStatelessService.cs in the project 'SubscribingStat ```csharp internal sealed class SubscribingStatelessService : SubscriberStatelessServiceBase { - public SubscribingStatelessService(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext, brokerClient) + public SubscribingStatelessService(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) + : base(serviceContext, brokerClient) { } diff --git a/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs b/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs index 7770614..93a3e73 100644 --- a/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs +++ b/ServiceFabric.PubSubActors.Tests/MockBrokerServiceLocator.cs @@ -1,7 +1,5 @@ using System; using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors; -using Microsoft.ServiceFabric.Services.Client; using ServiceFabric.PubSubActors.Helpers; using ServiceFabric.PubSubActors.State; @@ -19,16 +17,6 @@ public Task RegisterAsync(Uri brokerServiceName) return Task.CompletedTask; } - public Task GetPartitionForMessageAsync(string messageTypeName, Uri brokerServiceName) - { - return Task.FromResult(null); - } - - public Task GetPartitionForMessageAsync(object message, Uri brokerServiceName) - { - return Task.FromResult(null); - } - public Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName = null) { return Task.FromResult(new MockBrokerService()); @@ -42,26 +30,6 @@ public Task GetBrokerServiceForMessageAsync(string messageTypeNa public class MockBrokerService : IBrokerService { - public Task RegisterSubscriberAsync(ActorReference actor, string messageTypeName, string routingKey = null) - { - return Task.CompletedTask; - } - - public Task UnregisterSubscriberAsync(ActorReference actor, string messageTypeName, bool flushQueue) - { - return Task.CompletedTask; - } - - public Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, string routingKey = null) - { - return Task.CompletedTask; - } - - public Task UnregisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, bool flushQueue) - { - return Task.CompletedTask; - } - public Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName) { return Task.CompletedTask; diff --git a/ServiceFabric.PubSubActors/BrokerService.cs b/ServiceFabric.PubSubActors/BrokerService.cs index 3396be8..070ef6d 100644 --- a/ServiceFabric.PubSubActors/BrokerService.cs +++ b/ServiceFabric.PubSubActors/BrokerService.cs @@ -24,9 +24,8 @@ public abstract class BrokerService : BrokerServiceBase /// /// /// - /// Use remoting v2? Ignored in netstandard. - protected BrokerService(StatefulServiceContext serviceContext, bool enableAutoDiscovery = true, bool useRemotingV2 = false) - : base(serviceContext, enableAutoDiscovery, useRemotingV2) + protected BrokerService(StatefulServiceContext serviceContext, bool enableAutoDiscovery = true) + : base(serviceContext, enableAutoDiscovery) { } @@ -36,9 +35,8 @@ protected BrokerService(StatefulServiceContext serviceContext, bool enableAutoDi /// /// /// - /// Use remoting v2? Ignored in netstandard. - protected BrokerService(StatefulServiceContext serviceContext, IReliableStateManagerReplica2 reliableStateManagerReplica, bool enableAutoDiscovery = true, bool useRemotingV2 = false) - : base(serviceContext, reliableStateManagerReplica, enableAutoDiscovery, useRemotingV2) + protected BrokerService(StatefulServiceContext serviceContext, IReliableStateManagerReplica2 reliableStateManagerReplica, bool enableAutoDiscovery = true) + : base(serviceContext, reliableStateManagerReplica, enableAutoDiscovery) { } diff --git a/ServiceFabric.PubSubActors/BrokerServiceBase.cs b/ServiceFabric.PubSubActors/BrokerServiceBase.cs index 17357ed..d0ccf71 100644 --- a/ServiceFabric.PubSubActors/BrokerServiceBase.cs +++ b/ServiceFabric.PubSubActors/BrokerServiceBase.cs @@ -6,7 +6,6 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Services.Communication.Runtime; @@ -29,7 +28,6 @@ public abstract class BrokerServiceBase : StatefulService, IBrokerService new ConcurrentDictionary(); private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1); - private readonly bool _useRemotingV2; /// /// Gets the state key for all subscriber queues. @@ -71,8 +69,7 @@ public abstract class BrokerServiceBase : StatefulService, IBrokerService /// /// /// - /// Use remoting v2? Ignored in netstandard. - protected BrokerServiceBase(StatefulServiceContext serviceContext, bool enableAutoDiscovery = true, bool useRemotingV2 = false) + protected BrokerServiceBase(StatefulServiceContext serviceContext, bool enableAutoDiscovery = true) : base(serviceContext) { if (enableAutoDiscovery) @@ -82,8 +79,6 @@ protected BrokerServiceBase(StatefulServiceContext serviceContext, bool enableAu .GetAwaiter() .GetResult(); } - - _useRemotingV2 = useRemotingV2; } /// @@ -92,9 +87,8 @@ protected BrokerServiceBase(StatefulServiceContext serviceContext, bool enableAu /// /// /// - /// Use remoting v2? Ignored in netstandard. protected BrokerServiceBase(StatefulServiceContext serviceContext, - IReliableStateManagerReplica2 reliableStateManagerReplica, bool enableAutoDiscovery = true, bool useRemotingV2 = false) + IReliableStateManagerReplica2 reliableStateManagerReplica, bool enableAutoDiscovery = true) : base(serviceContext, reliableStateManagerReplica) { if (enableAutoDiscovery) @@ -104,53 +98,80 @@ protected BrokerServiceBase(StatefulServiceContext serviceContext, .GetAwaiter() .GetResult(); } - - _useRemotingV2 = useRemotingV2; - } - /// - /// Registers an Actor as a subscriber for messages. - /// - /// Reference to the actor to register. - /// Full type name of message object. - /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. - public async Task RegisterSubscriberAsync(ActorReference actor, string messageTypeName, string routingKey) - { - var actorReference = new ActorReferenceWrapper(actor, routingKey); - await SubscribeAsync(actorReference, messageTypeName); - } - /// - /// Unregisters an Actor as a subscriber for messages. - /// - /// Reference to the actor to unsubscribe. - /// Full type name of message object. - /// Publish any remaining messages. - public async Task UnregisterSubscriberAsync(ActorReference actor, string messageTypeName, bool flushQueue) - { - var actorReference = new ActorReferenceWrapper(actor); - await UnsubscribeAsync(actorReference, messageTypeName, flushQueue); } + /// - /// Registers a service as a subscriber for messages. + /// Registers a Service or Actor as subscriber for messages of type /// + /// Reference to the Service or Actor to register. /// Full type name of message object. - /// Reference to the service to register. /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. - public async Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, string routingKey) + /// + public async Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName, string routingKey) { - var serviceReference = new ServiceReferenceWrapper(service, routingKey); - await SubscribeAsync(serviceReference, messageTypeName); + await WaitForInitializeAsync(CancellationToken.None); + + var myDictionary = await TimeoutRetryHelper.Execute((token, state) => StateManager.GetOrAddAsync>(messageTypeName)); + + await TimeoutRetryHelper.ExecuteInTransaction(StateManager, async (tx, token, state) => + { + var queueName = CreateQueueName(reference, messageTypeName); + + Func addValueFactory = key => + { + var newState = new BrokerServiceState(messageTypeName); + var subscriber = new Reference(reference, queueName); + newState = BrokerServiceState.AddSubscriber(newState, subscriber); + return newState; + }; + + Func updateValueFactory = (key, current) => + { + var subscriber = new Reference(reference, queueName); + var newState = BrokerServiceState.AddSubscriber(current, subscriber); + return newState; + }; + + await myDictionary.AddOrUpdateAsync(tx, Subscribers, addValueFactory, updateValueFactory); + + await CreateQueueAsync(tx, queueName); + + _queues.AddOrUpdate(queueName, reference, (key, old) => reference); + ServiceEventSourceMessage($"Registered subscriber: {reference.Name}"); + }, cancellationToken: CancellationToken.None); } + /// - /// Unregisters a service as a subscriber for messages. + /// Unregisters a Service or Actor as subscriber for messages of type /// - /// Full type name of message object. - /// Reference to the actor to unsubscribe. - /// Publish any remaining messages. - public async Task UnregisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, bool flushQueue) + /// + /// + /// + /// + public async Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName, bool flushQueue) { - var serviceReference = new ServiceReferenceWrapper(service); - await UnsubscribeAsync(serviceReference, messageTypeName, flushQueue); + await WaitForInitializeAsync(CancellationToken.None); + + var myDictionary = await TimeoutRetryHelper.Execute((token, state) => StateManager.GetOrAddAsync>(messageTypeName)); + var queueName = CreateQueueName(reference, messageTypeName); + + await TimeoutRetryHelper.ExecuteInTransaction(StateManager, async (tx, token, state) => + { + var subscribers = await myDictionary.TryGetValueAsync(tx, Subscribers, LockMode.Update); + if (subscribers.HasValue) + { + var newState = BrokerServiceState.RemoveSubscriber(subscribers.Value, reference); + await myDictionary.SetAsync(tx, Subscribers, newState); + } + + + await StateManager.RemoveAsync(tx, queueName); + + ServiceEventSourceMessage($"Unregistered subscriber: {reference.Name}"); + _queues.TryRemove(queueName, out reference); + }); } + /// /// Takes a published message and forwards it (indirectly) to all Subscribers. /// @@ -248,21 +269,8 @@ protected override async Task RunAsync(CancellationToken cancellationToken) protected override IEnumerable CreateServiceReplicaListeners() { //add the pubsub listener -#if NETSTANDARD2_0 yield return new ServiceReplicaListener(context => new Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportServiceRemotingListener(context, this), ListenerName); -#else - if (_useRemotingV2) - { - yield return new ServiceReplicaListener(context => - new Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportServiceRemotingListener(context, this), ListenerName); - } - else - { - yield return new ServiceReplicaListener(context => - new Microsoft.ServiceFabric.Services.Remoting.V1.FabricTransport.Runtime.FabricTransportServiceRemotingListener(context, this), ListenerName); - } -#endif } /// @@ -337,97 +345,12 @@ protected void ServiceEventSourceMessage(string message, [CallerMemberName] stri ServiceEventSourceMessageCallback?.Invoke($"{caller} - {message}"); } - /// - /// Registers a Service or Actor as subscriber for messages of type - /// - /// - /// - /// - public async Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName) - { - await WaitForInitializeAsync(CancellationToken.None); - - var myDictionary = await TimeoutRetryHelper.Execute((token, state) => StateManager.GetOrAddAsync>(messageTypeName)); - - await TimeoutRetryHelper.ExecuteInTransaction(StateManager, async (tx, token, state) => - { - var queueName = CreateQueueName(reference, messageTypeName); - var deadLetterQueueName = CreateDeadLetterQueueName(reference, messageTypeName); - - Func addValueFactory = key => - { - var newState = new BrokerServiceState(messageTypeName); - var subscriber = new Reference(reference, queueName, deadLetterQueueName); - newState = BrokerServiceState.AddSubscriber(newState, subscriber); - return newState; - }; - - Func updateValueFactory = (key, current) => - { - var subscriber = new Reference(reference, queueName, deadLetterQueueName); - var newState = BrokerServiceState.AddSubscriber(current, subscriber); - return newState; - }; - - await myDictionary.AddOrUpdateAsync(tx, Subscribers, addValueFactory, updateValueFactory); - - await CreateQueueAsync(tx, queueName); - await CreateQueueAsync(tx, deadLetterQueueName); - - _queues.AddOrUpdate(queueName, reference, (key, old) => reference); - ServiceEventSourceMessage($"Registered subscriber: {reference.Name}"); - }, cancellationToken: CancellationToken.None); - } - protected abstract Task CreateQueueAsync(ITransaction tx, string queueName); - - /// - /// Unregisters a Service or Actor as subscriber for messages of type - /// - /// - /// - /// - /// - public async Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName, bool flushQueue) - { - await WaitForInitializeAsync(CancellationToken.None); - - var myDictionary = await TimeoutRetryHelper.Execute((token, state) => StateManager.GetOrAddAsync>(messageTypeName)); - var queueName = CreateQueueName(reference, messageTypeName); - var deadLetterQueueName = CreateDeadLetterQueueName(reference, messageTypeName); - - await TimeoutRetryHelper.ExecuteInTransaction(StateManager, async (tx, token, state) => - { - var subscribers = await myDictionary.TryGetValueAsync(tx, Subscribers, LockMode.Update); - if (subscribers.HasValue) - { - var newState = BrokerServiceState.RemoveSubscriber(subscribers.Value, reference); - await myDictionary.SetAsync(tx, Subscribers, newState); - } - - - await StateManager.RemoveAsync(tx, queueName); - await StateManager.RemoveAsync(tx, deadLetterQueueName); - - ServiceEventSourceMessage($"Unregistered subscriber: {reference.Name}"); - _queues.TryRemove(queueName, out reference); - }); - } - /// /// Creates a queuename to use for this reference. (message specific) /// /// - private static string CreateDeadLetterQueueName(ReferenceWrapper reference, string messageTypeName) - { - return $"{messageTypeName}_{reference.GetDeadLetterQueueName()}"; - } - - /// - /// Creates a deadletter queuename to use for this reference. (not message specific) - /// - /// private static string CreateQueueName(ReferenceWrapper reference, string messageTypeName) { return $"{messageTypeName}_{reference.GetQueueName()}"; diff --git a/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs b/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs index 4d488e1..26544fb 100644 --- a/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs +++ b/ServiceFabric.PubSubActors/BrokerServiceUnordered.cs @@ -24,9 +24,8 @@ public abstract class BrokerServiceUnordered : BrokerServiceBase /// /// /// - /// Use remoting v2? Ignored in netstandard. - protected BrokerServiceUnordered(StatefulServiceContext serviceContext, bool enableAutoDiscovery = true, bool useRemotingV2 = false) - : base(serviceContext, enableAutoDiscovery, useRemotingV2) + protected BrokerServiceUnordered(StatefulServiceContext serviceContext, bool enableAutoDiscovery = true) + : base(serviceContext, enableAutoDiscovery) { } @@ -36,9 +35,8 @@ protected BrokerServiceUnordered(StatefulServiceContext serviceContext, bool ena /// /// /// - /// Use remoting v2? Ignored in netstandard. - protected BrokerServiceUnordered(StatefulServiceContext serviceContext, IReliableStateManagerReplica2 reliableStateManagerReplica, bool enableAutoDiscovery = true, bool useRemotingV2 = false) - : base(serviceContext, reliableStateManagerReplica, enableAutoDiscovery, useRemotingV2) + protected BrokerServiceUnordered(StatefulServiceContext serviceContext, IReliableStateManagerReplica2 reliableStateManagerReplica, bool enableAutoDiscovery = true) + : base(serviceContext, reliableStateManagerReplica, enableAutoDiscovery) { } diff --git a/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs b/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs index 6231857..a86be3e 100644 --- a/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs +++ b/ServiceFabric.PubSubActors/Helpers/BrokerServiceLocator.cs @@ -16,30 +16,17 @@ public class BrokerServiceLocator : IBrokerServiceLocator private static ServicePartitionList _cachedPartitions; private static Uri _cachedBrokerUri; private readonly FabricClient _fabricClient; - private const string _brokerName = nameof(BrokerService); + private const string BrokerName = nameof(BrokerService); private readonly IServiceProxyFactory _serviceProxyFactory; /// /// Creates a new default instance. /// - public BrokerServiceLocator(bool useRemotingV2 = false, IHashingHelper hashingHelper = null) + public BrokerServiceLocator(IHashingHelper hashingHelper = null) { _hashingHelper = hashingHelper ?? new HashingHelper(); _fabricClient = new FabricClient(); - -#if NETSTANDARD2_0 - _serviceProxyFactory = new ServiceProxyFactory(c => new FabricTransportServiceRemotingClientFactory()); -#else - if (useRemotingV2) - { - _serviceProxyFactory = new ServiceProxyFactory(c => new FabricTransportServiceRemotingClientFactory()); - } - else - { - _serviceProxyFactory = new ServiceProxyFactory(); - } -#endif } @@ -47,7 +34,24 @@ public BrokerServiceLocator(bool useRemotingV2 = false, IHashingHelper hashingHe public async Task RegisterAsync(Uri brokerServiceName) { var activationContext = FabricRuntime.GetActivationContext(); - await _fabricClient.PropertyManager.PutPropertyAsync(new Uri(activationContext.ApplicationName), _brokerName, brokerServiceName.ToString()); + await _fabricClient.PropertyManager.PutPropertyAsync(new Uri(activationContext.ApplicationName), BrokerName, brokerServiceName.ToString()); + } + + /// + public async Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName = null) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + var resolvedPartition = await GetPartitionForMessageAsync(message, brokerServiceName); + return _serviceProxyFactory.CreateServiceProxy( + brokerServiceName ?? await LocateAsync(), resolvedPartition, listenerName: BrokerServiceBase.ListenerName); + } + + /// + public async Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName = null) + { + var resolvedPartition = await GetPartitionForMessageAsync(messageTypeName, brokerServiceName); + return _serviceProxyFactory.CreateServiceProxy( + brokerServiceName ?? await LocateAsync(), resolvedPartition, listenerName: BrokerServiceBase.ListenerName); } /// @@ -109,15 +113,17 @@ private async Task LocateAsync(Uri applicationName) return property != null ? new Uri(property.GetValue()) : null; } + private async Task GetBrokerPropertyOrNull(string applicationName) { return await GetBrokerPropertyOrNull(new Uri(applicationName)); } + private async Task GetBrokerPropertyOrNull(Uri applicationName) { try { - return await _fabricClient.PropertyManager.GetPropertyAsync(applicationName, _brokerName); + return await _fabricClient.PropertyManager.GetPropertyAsync(applicationName, BrokerName); } catch { @@ -126,8 +132,13 @@ private async Task GetBrokerPropertyOrNull(Uri applicationName) return null; } - /// - public async Task GetPartitionForMessageAsync(string messageTypeName, Uri brokerServiceName) + /// + /// Resolves the to send the message to, based on message type name. + /// + /// Full type name of message object. + /// + /// + private async Task GetPartitionForMessageAsync(string messageTypeName, Uri brokerServiceName) { if (_cachedPartitions == null) { @@ -152,37 +163,17 @@ public async Task GetPartitionForMessageAsync(string messag return resolvedPartition; } - /// - public Task GetPartitionForMessageAsync(object message, Uri brokerServiceName) + /// + /// Resolves the to send the message to, based on message's type. + /// + /// The message to publish + /// + /// + private Task GetPartitionForMessageAsync(object message, Uri brokerServiceName) { if (message == null) throw new ArgumentNullException(nameof(message)); string messageTypeName = message.GetType().FullName; return GetPartitionForMessageAsync(messageTypeName, brokerServiceName); } - - /// - public async Task GetBrokerServiceForMessageAsync(object message, Uri brokerServiceName = null) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - if (brokerServiceName == null) - { - brokerServiceName = await LocateAsync(); - } - var resolvedPartition = await GetPartitionForMessageAsync(message, brokerServiceName); - var brokerService = _serviceProxyFactory.CreateServiceProxy(brokerServiceName, resolvedPartition, listenerName: BrokerServiceBase.ListenerName); - return brokerService; - } - - /// - public async Task GetBrokerServiceForMessageAsync(string messageTypeName, Uri brokerServiceName = null) - { - if (brokerServiceName == null) - { - brokerServiceName = await LocateAsync(); - } - var resolvedPartition = await GetPartitionForMessageAsync(messageTypeName, brokerServiceName); - var brokerService = _serviceProxyFactory.CreateServiceProxy(brokerServiceName, resolvedPartition, listenerName: BrokerServiceBase.ListenerName); - return brokerService; - } } } diff --git a/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs b/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs index f4f1339..f5bd070 100644 --- a/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs +++ b/ServiceFabric.PubSubActors/Helpers/IBrokerServiceLocator.cs @@ -19,22 +19,6 @@ public interface IBrokerServiceLocator /// Task RegisterAsync(Uri brokerServiceName); - /// - /// Resolves the to send the message to, based on message type name. - /// - /// Full type name of message object. - /// - /// - Task GetPartitionForMessageAsync(string messageTypeName, Uri brokerServiceName); - - /// - /// Resolves the to send the message to, based on message's type. - /// - /// The message to publish - /// - /// - Task GetPartitionForMessageAsync(object message, Uri brokerServiceName); - /// /// Gets the instance for the provided /// diff --git a/ServiceFabric.PubSubActors/IBrokerService.cs b/ServiceFabric.PubSubActors/IBrokerService.cs index 580d021..aa6e10d 100644 --- a/ServiceFabric.PubSubActors/IBrokerService.cs +++ b/ServiceFabric.PubSubActors/IBrokerService.cs @@ -9,38 +9,6 @@ namespace ServiceFabric.PubSubActors /// public interface IBrokerService : IService { - /// - /// Registers an Actor as a subscriber for messages. - /// - /// Reference to the actor to register. - /// The full type name of the message to subscribe to. - /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. - Task RegisterSubscriberAsync(Microsoft.ServiceFabric.Actors.ActorReference actor, string messageTypeName, string routingKey); - - /// - /// Unregisters an Actor as a subscriber for messages. - /// - /// The full type name of the message to subscribe to. - /// Reference to the actor to unregister. - /// Publish any remaining messages. - Task UnregisterSubscriberAsync(Microsoft.ServiceFabric.Actors.ActorReference actor, string messageTypeName, bool flushQueue); - - /// - /// Registers a service as a subscriber for messages. - /// - /// The full type name of the message to subscribe to. - /// Reference to the Service to register. - /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. - Task RegisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, string routingKey); - - /// - /// Unregisters a service as a subscriber for messages. - /// - /// The full type name of the message to subscribe to. - /// Reference to the Service to unregister. - /// Publish any remaining messages. - Task UnregisterServiceSubscriberAsync(ServiceReference service, string messageTypeName, bool flushQueue); - /// /// Registers a Service or Actor as a subscriber for messages. /// diff --git a/ServiceFabric.PubSubActors/State/BrokerServiceState.cs b/ServiceFabric.PubSubActors/State/BrokerServiceState.cs index d5dde51..6f0b061 100644 --- a/ServiceFabric.PubSubActors/State/BrokerServiceState.cs +++ b/ServiceFabric.PubSubActors/State/BrokerServiceState.cs @@ -91,13 +91,10 @@ public class Reference [DataMember] public readonly string QueueName; - [DataMember] public readonly string DeadLetterQueueName; - - public Reference(ReferenceWrapper serviceOrActorReference, string queueName, string deadLetterQueueName) + public Reference(ReferenceWrapper serviceOrActorReference, string queueName) { ServiceOrActorReference = serviceOrActorReference; QueueName = queueName; - DeadLetterQueueName = deadLetterQueueName; } } } diff --git a/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs b/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs index d3e6825..fa56fdf 100644 --- a/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs +++ b/ServiceFabric.PubSubActors/State/ReferenceWrapper.cs @@ -79,14 +79,6 @@ public string GetQueueName() { return GetHashCode().ToString(); } - /// - /// Creates a dead-letter queue name to use for this reference. (not message specific) - /// - /// - public string GetDeadLetterQueueName() - { - return $"DeadLetters_{GetQueueName()}"; - } /// /// Determines whether to deliver the message to the subscriber, based on and . diff --git a/ServiceFabric.PubSubActors/State/ServiceReference.cs b/ServiceFabric.PubSubActors/State/ServiceReference.cs index e3229f2..163526c 100644 --- a/ServiceFabric.PubSubActors/State/ServiceReference.cs +++ b/ServiceFabric.PubSubActors/State/ServiceReference.cs @@ -28,10 +28,6 @@ public class ServiceReference [DataMember(IsRequired = false)] public string PartitionName { get; set; } - [Obsolete("Don't use this member. It's here for backwards compat.", true)] - [DataMember(IsRequired = false)] - public long? PartitionID { get; set; } - [DataMember(IsRequired = false)] public Guid PartitionGuid { get; set; } diff --git a/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs b/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs index 89c3aff..1e11638 100644 --- a/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs +++ b/ServiceFabric.PubSubActors/State/ServiceReferenceWrapper.cs @@ -1,5 +1,6 @@ using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; +using Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client; using ServiceFabric.PubSubActors.Subscriber; using System; using System.Fabric; @@ -14,7 +15,8 @@ namespace ServiceFabric.PubSubActors.State [DataContract] public class ServiceReferenceWrapper : ReferenceWrapper { - private static readonly Lazy ServiceProxyFactoryLazy = new Lazy(()=> new ServiceProxyFactory()); + private static readonly Lazy ServiceProxyFactoryLazy = + new Lazy(() => new ServiceProxyFactory(c => new FabricTransportServiceRemotingClientFactory())); public override string Name => ServiceReference.Description; From f664efc4310004cecefc9796bb1b0c9c62611c44 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Fri, 1 Mar 2019 14:12:43 -0800 Subject: [PATCH 07/11] Updated BrokerClient to support generic usage of Subscribe() and Unsubscribe for the case when users subscribe manually, instead of using the Subscribe attribute. Used extension methods instead of adding a bunch of overloads to the interface. --- README.md | 2 +- .../MockBrokerServiceLocator.cs | 2 +- .../BrokerServiceBase.cs | 7 +- .../Helpers/BrokerClient.cs | 167 ++++++++++++------ .../Helpers/IBrokerClient.cs | 59 +------ ServiceFabric.PubSubActors/IBrokerService.cs | 3 +- .../Subscriber/LongRunningTaskSubscriber.cs | 4 +- .../StatefulSubscriberServiceBootstrapper.cs | 5 +- .../StatelessSubscriberServiceBootstrapper.cs | 5 +- .../SubscriberStatefulServiceBase.cs | 6 +- .../SubscriberStatelessServiceBase.cs | 6 +- 11 files changed, 142 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index 71b324e..1641b43 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ internal class SubscribingActor : Actor, ISubscriberActor protected override async Task OnActivateAsync() { - await _brokerClient.SubscribeAsync(this, typeof(PublishedMessageOne), HandleMessageOne); + await _brokerClient.SubscribeAsync /// /// - /// /// - public async Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName, bool flushQueue) + public async Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName) { await WaitForInitializeAsync(CancellationToken.None); @@ -269,8 +269,7 @@ protected override async Task RunAsync(CancellationToken cancellationToken) protected override IEnumerable CreateServiceReplicaListeners() { //add the pubsub listener - yield return new ServiceReplicaListener(context => - new Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportServiceRemotingListener(context, this), ListenerName); + yield return new ServiceReplicaListener(context => new FabricTransportServiceRemotingListener(context, this), ListenerName); } /// diff --git a/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs index e63ae59..7d4c9b1 100644 --- a/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs +++ b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs @@ -24,53 +24,29 @@ public BrokerClient(IBrokerServiceLocator brokerServiceLocator = null) _brokerServiceLocator = brokerServiceLocator ?? new BrokerServiceLocator(); } - /// - /// Publish a message. - /// - /// - /// - public async Task PublishMessageAsync(object message) + /// + public async Task PublishMessageAsync(T message) where T : class { var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(message); await brokerService.PublishMessageAsync(message.CreateMessageWrapper()); } - /// - public Task SubscribeAsync(StatelessService service, Type messageType, Func handler, string listenerName = null) where T : class - { - return SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); - } - - /// - public Task SubscribeAsync(StatefulService service, Type messageType, Func handler, string listenerName = null) where T : class + /// + public async Task SubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType, Func handler) where T : class { - return SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); - } - - /// - public Task SubscribeAsync(ActorBase actor, Type messageType, Func handler) where T : class - { - return SubscribeAsync(CreateReferenceWrapper(actor), messageType, handler); - } - - /// - public Task UnsubscribeAsync(StatelessService service, Type messageType, bool flush) - { - return UnsubscribeAsync(CreateReferenceWrapper(service), messageType, flush); - } - - /// - public Task UnsubscribeAsync(StatefulService service, Type messageType, bool flush) - { - return UnsubscribeAsync(CreateReferenceWrapper(service), messageType, flush); + Handlers[messageType] = message => handler((T)message); + var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType); + await brokerService.SubscribeAsync(referenceWrapper, messageType.FullName); } - /// - public Task UnsubscribeAsync(ActorBase actor, Type messageType, bool flush) + /// + public async Task UnsubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType) { - return UnsubscribeAsync(CreateReferenceWrapper(actor), messageType, flush); + var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType); + await brokerService.UnsubscribeAsync(referenceWrapper, messageType.FullName); } + /// public Task ProcessMessageAsync(MessageWrapper messageWrapper) { var messageType = Assembly.Load(messageWrapper.Assembly).GetType(messageWrapper.MessageType, true); @@ -86,26 +62,113 @@ public Task ProcessMessageAsync(MessageWrapper messageWrapper) return Task.FromResult(true); } + } + + public static class BrokerClientExtensions + { + // subscribe/unsubscribe using Generic type (useful when subscibing manually) /// - /// Registers a Service or Actor as a subscriber for messages of type with the . + /// Registers this StatelessService as a subscriber for messages of type with the . /// + /// + /// + /// + /// /// - private async Task SubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType, Func handler) where T : class + public static Task SubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Func handler, string listenerName = null) where T : class { - Handlers[messageType] = message => handler((T)message); - var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.FullName); - await brokerService.SubscribeAsync(referenceWrapper, messageType.FullName); + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), typeof(T), handler); + } + + /// + /// Registers this StatefulService as a subscriber for messages of type with the . + /// + /// + /// + /// + /// + /// + public static Task SubscribeAsync(this IBrokerClient brokerClient, StatefulService service, Func handler, string listenerName = null) where T : class + { + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), typeof(T), handler); } /// - /// Unregisters a Service or Actor as a subscriber for messages of type with the . + /// Registers this Actor as a subscriber for messages of type with the . /// + /// + /// + /// /// - private async Task UnsubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType, bool flushQueue) + public static Task SubscribeAsync(this IBrokerClient brokerClient, ActorBase actor, Func handler) where T : class + { + return brokerClient.SubscribeAsync(CreateReferenceWrapper(actor), typeof(T), handler); + } + + /// + /// Unregisters this StatelessService as a subscriber for messages of type with the . + /// + /// + /// + /// + public static Task UnsubscribeAsync(this IBrokerClient brokerClient, StatelessService service) where T : class + { + return brokerClient.UnsubscribeAsync(CreateReferenceWrapper(service), typeof(T)); + } + + /// + /// Unregisters this StatefulService as a subscriber for messages of type with the . + /// + /// + /// + /// + public static Task UnsubscribeAsync(this IBrokerClient brokerClient, StatefulService service) where T : class + { + return brokerClient.UnsubscribeAsync(CreateReferenceWrapper(service), typeof(T)); + } + + /// + /// Unregisters this Actor as a subscriber for messages of type with the . + /// + /// + /// + /// + public static Task UnsubscribeAsync(this IBrokerClient brokerClient, ActorBase actor) where T : class + { + return brokerClient.UnsubscribeAsync(CreateReferenceWrapper(actor), typeof(T)); + } + + // subscribe/unsubscribe using Type (useful when processing Subscribe attributes) + + internal static Task SubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Type messageType, Func handler, string listenerName = null) where T : class + { + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); + } + + internal static Task SubscribeAsync(this IBrokerClient brokerClient, StatefulService service, Type messageType, Func handler, string listenerName = null) where T : class + { + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); + } + + internal static Task SubscribeAsync(this IBrokerClient brokerClient, ActorBase actor, Type messageType, Func handler) where T : class + { + return brokerClient.SubscribeAsync(CreateReferenceWrapper(actor), messageType, handler); + } + + internal static Task UnsubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Type messageType) + { + return brokerClient.UnsubscribeAsync(CreateReferenceWrapper(service), messageType); + } + + internal static Task UnsubscribeAsync(this IBrokerClient brokerClient, StatefulService service, Type messageType) + { + return brokerClient.UnsubscribeAsync(CreateReferenceWrapper(service), messageType); + } + + internal static Task UnsubscribeAsync(this IBrokerClient brokerClient, ActorBase actor, Type messageType) { - var brokerService = await _brokerServiceLocator.GetBrokerServiceForMessageAsync(messageType.FullName); - await brokerService.UnsubscribeAsync(referenceWrapper, messageType.FullName, flushQueue); + return brokerClient.UnsubscribeAsync(CreateReferenceWrapper(actor), messageType); } /// @@ -115,7 +178,7 @@ private async Task UnsubscribeAsync(ReferenceWrapper referenceWrapper, Type mess /// /// /// - private ReferenceWrapper CreateReferenceWrapper(StatelessService service, string listenerName = null) + private static ReferenceWrapper CreateReferenceWrapper(this StatelessService service, string listenerName = null) { if (service == null) throw new ArgumentNullException(nameof(service)); var servicePartition = GetPropertyValue(service, "Partition"); @@ -129,7 +192,7 @@ private ReferenceWrapper CreateReferenceWrapper(StatelessService service, string /// /// /// - private ReferenceWrapper CreateReferenceWrapper(StatefulService service, string listenerName = null) + private static ReferenceWrapper CreateReferenceWrapper(this StatefulService service, string listenerName = null) { if (service == null) throw new ArgumentNullException(nameof(service)); var servicePartition = GetPropertyValue(service, "Partition"); @@ -142,7 +205,7 @@ private ReferenceWrapper CreateReferenceWrapper(StatefulService service, string /// /// /// - private ReferenceWrapper CreateReferenceWrapper(ActorBase actor) + private static ReferenceWrapper CreateReferenceWrapper(this ActorBase actor) { if (actor == null) throw new ArgumentNullException(nameof(actor)); return new ActorReferenceWrapper(ActorReference.Get(actor)); @@ -155,7 +218,7 @@ private ReferenceWrapper CreateReferenceWrapper(ActorBase actor) /// /// (optional) The name of the listener that is used to communicate with the service /// - private ServiceReference CreateServiceReference(ServiceContext context, ServicePartitionInformation info, string listenerName = null) + private static ServiceReference CreateServiceReference(ServiceContext context, ServicePartitionInformation info, string listenerName = null) { var serviceReference = new ServiceReference { @@ -178,11 +241,11 @@ private ServiceReference CreateServiceReference(ServiceContext context, ServiceP return serviceReference; } - private TProperty GetPropertyValue(TClass instance, string propertyName) + private static TProperty GetPropertyValue(TClass instance, string propertyName) { return (TProperty)(typeof(TClass) - .GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic)? - .GetValue(instance) ?? throw new ArgumentNullException($"Unable to find property: '{propertyName}' on: '{instance}'")); + .GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic)? + .GetValue(instance) ?? throw new ArgumentNullException($"Unable to find property: '{propertyName}' on: '{instance}'")); } } } \ No newline at end of file diff --git a/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs b/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs index 71f05f4..59b7f50 100644 --- a/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs +++ b/ServiceFabric.PubSubActors/Helpers/IBrokerClient.cs @@ -1,7 +1,5 @@ using System; using System.Threading.Tasks; -using Microsoft.ServiceFabric.Actors.Runtime; -using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.State; namespace ServiceFabric.PubSubActors.Helpers @@ -9,70 +7,31 @@ namespace ServiceFabric.PubSubActors.Helpers public interface IBrokerClient { /// - /// Publish a message. + /// Publish a message of type . /// /// /// - Task PublishMessageAsync(object message); + Task PublishMessageAsync(T message) where T : class; /// - /// Registers this StatelessService as a subscriber for messages of type with the . + /// Registers this Service or Actor as a subscriber for messages of type with the . /// - /// + /// /// /// - /// /// - Task SubscribeAsync(StatelessService service, Type messageType, Func handler, string listenerName = null) where T : class; + Task SubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType, Func handler) where T : class; /// - /// Registers this StatefulService as a subscriber for messages of type with the . + /// Unregisters this Service or Actor as a subscriber for messages of type with the . /// - /// + /// /// - /// - /// - /// - Task SubscribeAsync(StatefulService service, Type messageType, Func handler, string listenerName = null) where T : class; - - /// - /// Registers this Actor as a subscriber for messages of type with the . - /// - /// - /// - /// - /// - Task SubscribeAsync(ActorBase actor, Type messageType, Func handler) where T : class; - - /// - /// Unregisters this StatelessService as a subscriber for messages of type with the . - /// - /// - /// - /// - /// - Task UnsubscribeAsync(StatelessService service, Type messageType, bool flush); - - /// - /// Unregisters this StatefulService as a subscriber for messages of type with the . - /// - /// - /// - /// - /// - Task UnsubscribeAsync(StatefulService service, Type messageType, bool flush); - - /// - /// Unregisters this Actor as a subscriber for messages of type with the . - /// - /// - /// - /// /// - Task UnsubscribeAsync(ActorBase actor, Type messageType, bool flush); + Task UnsubscribeAsync(ReferenceWrapper referenceWrapper, Type messageType); /// - /// Given a , call the handler given for that type when was called. + /// Given a , call the handler given for that type when was called. /// /// /// diff --git a/ServiceFabric.PubSubActors/IBrokerService.cs b/ServiceFabric.PubSubActors/IBrokerService.cs index aa6e10d..7820051 100644 --- a/ServiceFabric.PubSubActors/IBrokerService.cs +++ b/ServiceFabric.PubSubActors/IBrokerService.cs @@ -21,8 +21,7 @@ public interface IBrokerService : IService /// /// The full type name of the message to subscribe to. /// Reference to the service or actor to unregister. - /// Publish any remaining messages. - Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName, bool flushQueue); + Task UnsubscribeAsync(ReferenceWrapper reference, string messageTypeName); /// /// Takes a published message and forwards it (indirectly) to all Subscribers. diff --git a/ServiceFabric.PubSubActors/Subscriber/LongRunningTaskSubscriber.cs b/ServiceFabric.PubSubActors/Subscriber/LongRunningTaskSubscriber.cs index 557145e..36908d0 100644 --- a/ServiceFabric.PubSubActors/Subscriber/LongRunningTaskSubscriber.cs +++ b/ServiceFabric.PubSubActors/Subscriber/LongRunningTaskSubscriber.cs @@ -8,7 +8,7 @@ using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Services.Communication.Runtime; -using Microsoft.ServiceFabric.Services.Remoting.Runtime; +using Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using Newtonsoft.Json; using ServiceFabric.PubSubActors.Helpers; @@ -62,7 +62,7 @@ protected LongRunningTaskSubscriberService(StatefulServiceContext serviceContext /// protected override IEnumerable CreateServiceReplicaListeners() { - return this.CreateServiceRemotingReplicaListeners(); //remoting listener + yield return new ServiceReplicaListener(context => new FabricTransportServiceRemotingListener(context, this)); //remoting listener } /// diff --git a/ServiceFabric.PubSubActors/Subscriber/StatefulSubscriberServiceBootstrapper.cs b/ServiceFabric.PubSubActors/Subscriber/StatefulSubscriberServiceBootstrapper.cs index 6e4322c..a4a0639 100644 --- a/ServiceFabric.PubSubActors/Subscriber/StatefulSubscriberServiceBootstrapper.cs +++ b/ServiceFabric.PubSubActors/Subscriber/StatefulSubscriberServiceBootstrapper.cs @@ -128,8 +128,7 @@ private async Task RegisterSubscriptions() } catch (Exception ex) { - _loggingCallback?.Invoke( - $"Failed to register subscriptions for service '{_context.ServiceName}'. Error: {ex}"); + _loggingCallback?.Invoke($"Failed to register subscriptions for service '{_context.ServiceName}'. Error: {ex}"); } } @@ -141,7 +140,7 @@ private async Task UnregisterSubscriptions() { foreach (var subscription in _service.DiscoverMessageHandlers()) { - await _brokerClient.UnsubscribeAsync(_service, subscription.Key, false).ConfigureAwait(false); + await _brokerClient.UnsubscribeAsync(_service, subscription.Key).ConfigureAwait(false); } } catch (Exception ex) diff --git a/ServiceFabric.PubSubActors/Subscriber/StatelessSubscriberServiceBootstrapper.cs b/ServiceFabric.PubSubActors/Subscriber/StatelessSubscriberServiceBootstrapper.cs index e396080..cbf1323 100644 --- a/ServiceFabric.PubSubActors/Subscriber/StatelessSubscriberServiceBootstrapper.cs +++ b/ServiceFabric.PubSubActors/Subscriber/StatelessSubscriberServiceBootstrapper.cs @@ -128,8 +128,7 @@ private async Task RegisterSubscriptions() } catch (Exception ex) { - _loggingCallback?.Invoke( - $"Failed to register subscriptions for service '{_context.ServiceName}'. Error: {ex}"); + _loggingCallback?.Invoke($"Failed to register subscriptions for service '{_context.ServiceName}'. Error: {ex}"); } } @@ -141,7 +140,7 @@ private async Task UnregisterSubscriptions() { foreach (var subscription in _service.DiscoverMessageHandlers()) { - await _brokerClient.UnsubscribeAsync(_service, subscription.Key, false).ConfigureAwait(false); + await _brokerClient.UnsubscribeAsync(_service, subscription.Key).ConfigureAwait(false); } } catch (Exception ex) diff --git a/ServiceFabric.PubSubActors/Subscriber/SubscriberStatefulServiceBase.cs b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatefulServiceBase.cs index 9e7b778..ecb436d 100644 --- a/ServiceFabric.PubSubActors/Subscriber/SubscriberStatefulServiceBase.cs +++ b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatefulServiceBase.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Services.Communication.Runtime; -using Microsoft.ServiceFabric.Services.Remoting.Runtime; +using Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Helpers; using ServiceFabric.PubSubActors.State; @@ -25,7 +25,7 @@ public class SubscriberStatefulServiceBase : StatefulService, ISubscriberService /// /// Set the Listener name so the remote Broker can find this service when there are multiple listeners available. /// - protected string ListenerName { get; set; } + protected string ListenerName { get; set; } = "SubscriberStatefulServiceRemotingListener"; /// /// Creates a new instance using the provided context. @@ -91,7 +91,7 @@ protected virtual async Task Subscribe() /// protected override IEnumerable CreateServiceReplicaListeners() { - return this.CreateServiceRemotingReplicaListeners(); + yield return new ServiceReplicaListener(context => new FabricTransportServiceRemotingListener(context, this), ListenerName); } /// diff --git a/ServiceFabric.PubSubActors/Subscriber/SubscriberStatelessServiceBase.cs b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatelessServiceBase.cs index b380a16..9289410 100644 --- a/ServiceFabric.PubSubActors/Subscriber/SubscriberStatelessServiceBase.cs +++ b/ServiceFabric.PubSubActors/Subscriber/SubscriberStatelessServiceBase.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Communication.Runtime; -using Microsoft.ServiceFabric.Services.Remoting.Runtime; +using Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using ServiceFabric.PubSubActors.Helpers; using ServiceFabric.PubSubActors.State; @@ -28,7 +28,7 @@ public abstract class SubscriberStatelessServiceBase : StatelessService, ISubscr /// /// Set the Listener name so the remote Broker can find this service when there are multiple listeners available. /// - protected string ListenerName { get; set; } + protected string ListenerName { get; set; } = "SubscriberStatelessServiceRemotingListener"; protected SubscriberStatelessServiceBase(StatelessServiceContext serviceContext, IBrokerClient brokerClient = null) : base(serviceContext) @@ -76,7 +76,7 @@ protected virtual async Task Subscribe() /// protected override IEnumerable CreateServiceInstanceListeners() { - return this.CreateServiceRemotingInstanceListeners(); + yield return new ServiceInstanceListener(context => new FabricTransportServiceRemotingListener(context, this), ListenerName); } /// From dc468d935020716e76fe476a18a4550c8bd4a895 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Mon, 4 Mar 2019 09:24:48 -0800 Subject: [PATCH 08/11] updated BrokerClient to support routing key, more work will be needed to support it in subscriber base classes and bootstrappers --- README.md | 2 +- .../Helpers/BrokerClient.cs | 42 +++++++++++-------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 1641b43..0c9307f 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ internal class SubscribingActor : Actor, ISubscriberActor protected override async Task OnActivateAsync() { - await _brokerClient.SubscribeAsync(this, HandleMessageOne); } public Task ReceiveMessageAsync(MessageWrapper message) diff --git a/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs index 7d4c9b1..c28074e 100644 --- a/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs +++ b/ServiceFabric.PubSubActors/Helpers/BrokerClient.cs @@ -75,10 +75,11 @@ public static class BrokerClientExtensions /// /// /// + /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. /// - public static Task SubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Func handler, string listenerName = null) where T : class + public static Task SubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Func handler, string listenerName = null, string routingKey = null) where T : class { - return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), typeof(T), handler); + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName, routingKey), typeof(T), handler); } /// @@ -88,10 +89,11 @@ public static Task SubscribeAsync(this IBrokerClient brokerClient, StatelessS /// /// /// + /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. /// - public static Task SubscribeAsync(this IBrokerClient brokerClient, StatefulService service, Func handler, string listenerName = null) where T : class + public static Task SubscribeAsync(this IBrokerClient brokerClient, StatefulService service, Func handler, string listenerName = null, string routingKey = null) where T : class { - return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), typeof(T), handler); + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName, routingKey), typeof(T), handler); } /// @@ -100,10 +102,11 @@ public static Task SubscribeAsync(this IBrokerClient brokerClient, StatefulSe /// /// /// + /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. /// - public static Task SubscribeAsync(this IBrokerClient brokerClient, ActorBase actor, Func handler) where T : class + public static Task SubscribeAsync(this IBrokerClient brokerClient, ActorBase actor, Func handler, string routingKey = null) where T : class { - return brokerClient.SubscribeAsync(CreateReferenceWrapper(actor), typeof(T), handler); + return brokerClient.SubscribeAsync(CreateReferenceWrapper(actor, routingKey), typeof(T), handler); } /// @@ -141,19 +144,19 @@ public static Task UnsubscribeAsync(this IBrokerClient brokerClient, ActorBas // subscribe/unsubscribe using Type (useful when processing Subscribe attributes) - internal static Task SubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Type messageType, Func handler, string listenerName = null) where T : class + internal static Task SubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Type messageType, Func handler, string listenerName = null, string routingKey = null) where T : class { - return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName, routingKey), messageType, handler); } - internal static Task SubscribeAsync(this IBrokerClient brokerClient, StatefulService service, Type messageType, Func handler, string listenerName = null) where T : class + internal static Task SubscribeAsync(this IBrokerClient brokerClient, StatefulService service, Type messageType, Func handler, string listenerName = null, string routingKey = null) where T : class { - return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName), messageType, handler); + return brokerClient.SubscribeAsync(CreateReferenceWrapper(service, listenerName, routingKey), messageType, handler); } - internal static Task SubscribeAsync(this IBrokerClient brokerClient, ActorBase actor, Type messageType, Func handler) where T : class + internal static Task SubscribeAsync(this IBrokerClient brokerClient, ActorBase actor, Type messageType, Func handler, string routingKey = null) where T : class { - return brokerClient.SubscribeAsync(CreateReferenceWrapper(actor), messageType, handler); + return brokerClient.SubscribeAsync(CreateReferenceWrapper(actor, routingKey), messageType, handler); } internal static Task UnsubscribeAsync(this IBrokerClient brokerClient, StatelessService service, Type messageType) @@ -176,13 +179,14 @@ internal static Task UnsubscribeAsync(this IBrokerClient brokerClient, ActorBase /// /// /// + /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. /// /// - private static ReferenceWrapper CreateReferenceWrapper(this StatelessService service, string listenerName = null) + private static ReferenceWrapper CreateReferenceWrapper(this StatelessService service, string listenerName = null, string routingKey = null) { if (service == null) throw new ArgumentNullException(nameof(service)); var servicePartition = GetPropertyValue(service, "Partition"); - return new ServiceReferenceWrapper(CreateServiceReference(service.Context, servicePartition.PartitionInfo, listenerName)); + return new ServiceReferenceWrapper(CreateServiceReference(service.Context, servicePartition.PartitionInfo, listenerName), routingKey); } /// @@ -190,25 +194,27 @@ private static ReferenceWrapper CreateReferenceWrapper(this StatelessService ser /// /// /// + /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. /// /// - private static ReferenceWrapper CreateReferenceWrapper(this StatefulService service, string listenerName = null) + private static ReferenceWrapper CreateReferenceWrapper(this StatefulService service, string listenerName = null, string routingKey = null) { if (service == null) throw new ArgumentNullException(nameof(service)); var servicePartition = GetPropertyValue(service, "Partition"); - return new ServiceReferenceWrapper(CreateServiceReference(service.Context, servicePartition.PartitionInfo, listenerName)); + return new ServiceReferenceWrapper(CreateServiceReference(service.Context, servicePartition.PartitionInfo, listenerName), routingKey); } /// /// Create a ReferenceWrapper object given this Actor. /// /// + /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. /// /// - private static ReferenceWrapper CreateReferenceWrapper(this ActorBase actor) + private static ReferenceWrapper CreateReferenceWrapper(this ActorBase actor, string routingKey = null) { if (actor == null) throw new ArgumentNullException(nameof(actor)); - return new ActorReferenceWrapper(ActorReference.Get(actor)); + return new ActorReferenceWrapper(ActorReference.Get(actor), routingKey); } /// From e10eb4e3302ee265dd07c6cb458bb9cfd5172288 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Mon, 4 Mar 2019 15:07:45 -0800 Subject: [PATCH 09/11] updated version, added migration tips --- README.md | 37 +++++++++++++++---- .../ServiceFabric.PubSubActors.csproj | 2 +- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0c9307f..b33b8ed 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,6 @@ Do you need to reliably broadcast messages between Actors and Services? This code will help you do that. It supports both Actors and Services as publishers and subscribers. -It uses extension methods to -- Actor -- StatelessService -- StatefulService - ## Contribute! Contributions are welcome. Please upgrade the package version with a minor tick if there are no breaking changes. And add a line to the readme.md, stating the changes, e.g. 'upgraded to SF version x.y.z'. @@ -17,6 +12,7 @@ Please also make sure all feature additions have a corresponding unit test. ## Release notes: +- 8.0.0 Major cleanup and usability improvements. Replaced Helper classes with a single `BrokerClient`. Removed obsolete code (BrokerActor, RelayBrokerActor, extension methods). Removed the `ServiceFabric.PubSubActors.Interfaces` library. Simplified the BrokerService interface. - 7.6.2 Fix routing key issue. - 7.6.1 Fix hashing helper null ref issue. - 7.6.0 Add routing key support, to support attribute based messaging. Fix hashing issue in dotnet core. @@ -58,7 +54,6 @@ Please also make sure all feature additions have a corresponding unit test. ## Nuget: https://www.nuget.org/packages/ServiceFabric.PubSubActors -https://www.nuget.org/packages/ServiceFabric.PubSubActors.Interfaces (obsolete as of v8.0) ## Getting started @@ -213,7 +208,7 @@ The code in `Program` will look like this: ```csharp var brokerClient = new BrokerClient(); ServiceRuntime.RegisterServiceAsync("SubscribingStatelessServiceType", - context => new StatelessSubscriberServiceBootstrapper(context, ctx => new SubscribingStatelessService (ctx, brokerClient), brokerClient).Build()) + context => new StatelessSubscriberServiceBootstrapper(context, ctx => new SubscribingStatelessService (ctx, brokerClient), brokerClient).Build()) .GetAwaiter().GetResult(); ``` @@ -285,7 +280,33 @@ And given a subscriber that is interested in Customers named 'Customer1'. The subscription would be registered like this: ```csharp -await brokerService.RegisterServiceSubscriberAsync(serviceReference, typeof(CustomerMessage).FullName, "Customer.Name=Customer1"); +await brokerClient.SubscribeAsync(this, HandleMessageOne, routingKey: "Customer.Name=Customer1"); ``` The routing key is queried by using `JToken.SelectToken`. More info [here](https://www.newtonsoft.com/json/help/html/SelectToken.htm). + + +## Upgrading to version 8 +Significant changes were made in v8.0.0, including breaking changes to interfaces and tools. +* BrokerActor and RelayBrokerActor were removed. Actors don't make a good Broker, use BrokerService instead. +* ServiceFabric.PubSubActors.Interfaces library was removed. Only the main library is required now. +* Obsolete extension methods were removed. +* Helper classes were removed and replaced with `BrokerClient`. +* V2 is the only supported Service Fabric Remoting version. + +Here are some tips to help you through the upgrade process: +1. Upgrade remoting to V2 + * v8.0 only supports remoting V2. If you are using .NET Standard, you should already be using V2 and you can skip this step. + * Refer to documentation here: [Upgrade From Remoting V1 to Remoting V2](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-remoting#upgrade-from-remoting-v1-to-remoting-v2) + * Upgrade the Broker first. Override `BrokerService.CreateServiceReplicaListeners()` to use the extension method mentioned in the above link so you can use the assembly attribute to set up listening on V1 and V2. + * Upgrade Publisher and Subscriber services. Use the `useRemotingV2` option when creating the BrokerServiceLocator that is used by Helper classes. +2. Upgrade the Broker. + * Remove the ServiceFabric.PubSubActors.Interfaces library and upgrade the ServiceFabric.PubSubActors library to 8.0. + * Publish message and Receive message are backwards compatible, so update BrokerService first and publishers and subscribers should continue to function. +3. Upgrade Subscribers. + * Register/Unregister has been replaced by Subscribe/Unsubscribe, so you won't be able to subscribe/unsubscribe until you update subscriber services. + * Remove the ServiceFabric.PubSubActors.Interfaces library and upgrade the ServiceFabric.PubSubActors library to 8.0. + * Extension methods and helper classes have been removed. If you are using any of them in your Subscriber services, they will need to be refactored to use the BrokerClient or one of the Subscriber base classes (see documentation above). +4. Upgrade Publishers. (Optional, publishing is backwards compatible) + * Remove the ServiceFabric.PubSubActors.Interfaces library and upgrade the ServiceFabric.PubSubActors library to 8.0. + * Extension method and helper classes have been removed. Use BrokerClient.PublishMessageAsync() instead. diff --git a/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj b/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj index cac6eba..b456a17 100644 --- a/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj +++ b/ServiceFabric.PubSubActors/ServiceFabric.PubSubActors.csproj @@ -3,7 +3,7 @@ ServiceFabric.PubSubActors adds pub/sub behaviour to your Reliable Actors and Services in Service Fabric. How to use this package: https://github.com/loekd/ServiceFabric.PubSubActors/blob/master/README.md 2019 ServiceFabric.PubSubActors - 7.6.2 + 8.0.0 Loek Duys net452;net46;netstandard2.0 x64 From a4b59d38b4902b9c52a72bdae88fef78850332be Mon Sep 17 00:00:00 2001 From: Loek Date: Tue, 5 Mar 2019 08:39:19 +0100 Subject: [PATCH 10/11] Add fix to branch --- .../GivenServiceReferenceWrapper.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ServiceFabric.PubSubActors.Tests/GivenServiceReferenceWrapper.cs b/ServiceFabric.PubSubActors.Tests/GivenServiceReferenceWrapper.cs index f8a86f8..85e40ed 100644 --- a/ServiceFabric.PubSubActors.Tests/GivenServiceReferenceWrapper.cs +++ b/ServiceFabric.PubSubActors.Tests/GivenServiceReferenceWrapper.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Reflection; using System.Runtime.Serialization; -using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; -using ServiceFabric.PubSubActors.Interfaces; using ServiceFabric.PubSubActors.State; namespace ServiceFabric.PubSubActors.Tests From de1b4e7e827ec6159b2d181cade03f2a098f0918 Mon Sep 17 00:00:00 2001 From: "Dana.Desrosiers" Date: Tue, 5 Mar 2019 09:04:55 -0800 Subject: [PATCH 11/11] fixed error in conflict resolution --- ServiceFabric.PubSubActors/BrokerServiceBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ServiceFabric.PubSubActors/BrokerServiceBase.cs b/ServiceFabric.PubSubActors/BrokerServiceBase.cs index 985a9be..08e61f7 100644 --- a/ServiceFabric.PubSubActors/BrokerServiceBase.cs +++ b/ServiceFabric.PubSubActors/BrokerServiceBase.cs @@ -106,9 +106,8 @@ protected BrokerServiceBase(StatefulServiceContext serviceContext, /// /// Reference to the Service or Actor to register. /// Full type name of message object. - /// Optional routing key to filter messages based on content. 'Key=Value' where Key is a message property path and Value is the value to match with message payload content. /// - public async Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName, string routingKey) + public async Task SubscribeAsync(ReferenceWrapper reference, string messageTypeName) { await WaitForInitializeAsync(CancellationToken.None);