/// <summary> /// Initializes a new instance of the <see cref="CommandProcessor"/> class. /// Use this constructor when both rpc support is required /// </summary> /// <param name="subscriberRegistry">The subscriber registry.</param> /// <param name="handlerFactory">The handler factory.</param> /// <param name="requestContextFactory">The request context factory.</param> /// <param name="policyRegistry">The policy registry.</param> /// <param name="mapperRegistry">The mapper registry.</param> /// <param name="outBox">The outbox</param> /// <param name="producerRegistry">The register of producers via whom we send messages over the external bus</param> /// <param name="replySubscriptions">The Subscriptions for creating the reply queues</param> /// <param name="responseChannelFactory">If we are expecting a response, then we need a channel to listen on</param> /// <param name="outboxTimeout">How long should we wait to write to the outbox</param> /// <param name="featureSwitchRegistry">The feature switch config provider.</param> /// <param name="inboxConfiguration">Do we want to insert an inbox handler into pipelines without the attribute. Null (default = no), yes = how to configure</param> /// <param name="boxTransactionConnectionProvider">The Box Connection Provider to use when Depositing into the outbox.</param> public CommandProcessor( IAmASubscriberRegistry subscriberRegistry, IAmAHandlerFactory handlerFactory, IAmARequestContextFactory requestContextFactory, IPolicyRegistry <string> policyRegistry, IAmAMessageMapperRegistry mapperRegistry, IAmAnOutbox <Message> outBox, IAmAProducerRegistry producerRegistry, IEnumerable <Subscription> replySubscriptions, int outboxTimeout = 300, IAmAFeatureSwitchRegistry featureSwitchRegistry = null, IAmAChannelFactory responseChannelFactory = null, InboxConfiguration inboxConfiguration = null, IAmABoxTransactionConnectionProvider boxTransactionConnectionProvider = null) : this(subscriberRegistry, handlerFactory, requestContextFactory, policyRegistry) { _mapperRegistry = mapperRegistry; _featureSwitchRegistry = featureSwitchRegistry; _responseChannelFactory = responseChannelFactory; _inboxConfiguration = inboxConfiguration; _boxTransactionConnectionProvider = boxTransactionConnectionProvider; _replySubscriptions = replySubscriptions; InitExtServiceBus(policyRegistry, outBox, outboxTimeout, producerRegistry); ConfigureCallbacks(producerRegistry); }
public ControlBusSenderFactoryTests() { s_fakeOutbox = A.Fake <IAmAnOutbox <Message> >(); s_fakeGateway = A.Fake <IAmAMessageProducer>(); s_senderFactory = new ControlBusSenderFactory(); }
/// <summary> /// Constructor for use with a Producer /// </summary> /// <param name="outBox">The outbox to store messages - use InMemoryInbox if you do not require a persistent outbox</param> /// <param name="asyncOutBox">The outbox to store messages - use InMemoryInbox if you do not require a persistent outbox</param> /// <param name="producer">The Message producer</param> /// <param name="asyncProducer">The Message producer's async interface</param> public BrighterMessaging(IAmAnOutbox <Message> outBox, IAmAnOutboxAsync <Message> asyncOutBox, IAmAMessageProducer producer, IAmAMessageProducerAsync asyncProducer) { OutBox = outBox; AsyncOutBox = asyncOutBox; Producer = producer; AsyncProducer = asyncProducer; }
//Create an instance of the ExternalBusServices if one not already set for this app. Note that we do not support reinitialization here, so once you have //set a command processor for the app, you can't call init again to set them - although the properties are not read-only so overwriting is possible //if needed as a "get out of gaol" card. private void InitExtServiceBus(IPolicyRegistry <string> policyRegistry, IAmAnOutbox <Message> outbox, int outboxTimeout, IAmAProducerRegistry producerRegistry) { if (_bus == null) { lock (padlock) { if (_bus == null) { if (producerRegistry == null) { throw new ConfigurationException("A producer registry is required to create an external bus"); } _bus = new ExternalBusServices(); if (outbox is IAmAnOutboxSync <Message> syncOutbox) { _bus.OutBox = syncOutbox; } if (outbox is IAmAnOutboxAsync <Message> asyncOutbox) { _bus.AsyncOutbox = asyncOutbox; } _bus.OutboxTimeout = outboxTimeout; _bus.PolicyRegistry = policyRegistry; _bus.ProducerRegistry = producerRegistry; } } } }
/// <summary> /// Constructor for use with a Producer /// </summary> /// <param name="outBox">The outbox to store messages - use InMemoryInbox if you do not require a persistent outbox</param> /// <param name="asyncOutBox">The outbox to store messages - use InMemoryInbox if you do not require a persistent outbox</param> /// <param name="producer">The Message producer</param> /// <param name="asyncProducer">The Message producer's async interface</param> /// <param name="useRequestReplyQueues">Use Request Reply Queues - This will need to set a Channel Factory as well.</param> public BrighterMessaging(IAmAnOutbox <Message> outBox, IAmAnOutboxAsync <Message> asyncOutBox, IAmAMessageProducer producer, IAmAMessageProducerAsync asyncProducer, bool useRequestReplyQueues = true) { OutBox = outBox; AsyncOutBox = asyncOutBox; Producer = producer; AsyncProducer = asyncProducer; UseRequestReplyQueues = useRequestReplyQueues; }
public void Repost(List <string> messageIds, IAmAnOutbox <Message> outBox, IAmAMessageProducer messageProducer) { var foundMessages = GetMessagesFromOutBox(outBox, messageIds); foreach (var foundMessage in foundMessages) { messageProducer.Send(foundMessage); } }
/// <summary> /// The <see cref="CommandProcessor"/> wants to support <see cref="CommandProcessor.Post{T}(T)"/> or <see cref="CommandProcessor.Repost"/> using an external bus. /// You need to provide a policy to specify how QoS issues, specifically <see cref="CommandProcessor.RETRYPOLICY "/> or <see cref="CommandProcessor.CIRCUITBREAKER "/> /// are handled by adding appropriate <see cref="Policies"/> when choosing this option. /// /// </summary> /// <param name="configuration">The Task Queues configuration.</param> /// <param name="outbox">The Outbox.</param> /// <param name="boxTransactionConnectionProvider"></param> /// <returns>INeedARequestContext.</returns> public INeedARequestContext ExternalBus(ExternalBusConfiguration configuration, IAmAnOutbox <Message> outbox, IAmABoxTransactionConnectionProvider boxTransactionConnectionProvider = null) { _useExternalBus = true; _producers = configuration.ProducerRegistry; _outbox = outbox; _overridingBoxTransactionConnectionProvider = boxTransactionConnectionProvider; _messageMapperRegistry = configuration.MessageMapperRegistry; _outboxWriteTimeout = configuration.OutboxWriteTimeout; return(this); }
/// <summary> /// The <see cref="CommandProcessor"/> wants to support <see cref="CommandProcessor.Post{T}(T)"/> or <see cref="CommandProcessor.Repost"/> using Task Queues. /// You need to provide a policy to specify how QoS issues, specifically <see cref="CommandProcessor.RETRYPOLICY "/> or <see cref="CommandProcessor.CIRCUITBREAKER "/> /// are handled by adding appropriate <see cref="Policies"/> when choosing this option. /// /// </summary> /// <param name="configuration">The Task Queues configuration.</param> /// <returns>INeedARequestContext.</returns> public INeedARequestContext TaskQueues(MessagingConfiguration configuration) { _useTaskQueues = true; _messageStore = configuration.OutBox; _asyncOutbox = configuration.AsyncOutbox; _messagingGateway = configuration.MessageProducer; _asyncMessagingGateway = configuration.AsyncMessageProducer; _messageMapperRegistry = configuration.MessageMapperRegistry; _messageStoreWriteTimeout = configuration.MessageStoreWriteTimeout; _messagingGatewaySendTimeout = configuration.MessagingGatewaySendTimeout; return(this); }
/// <summary> /// The <see cref="CommandProcessor"/> wants to support <see cref="CommandProcessor.Call{T}(T)"/> using RPC between client and server /// </summary> /// <param name="configuration"></param> /// <param name="outbox">The outbox</param> /// <param name="subscriptions">Subscriptions for creating reply queues</param> /// <returns></returns> public INeedARequestContext ExternalRPC(ExternalBusConfiguration configuration, IAmAnOutbox <Message> outbox, IEnumerable <Subscription> subscriptions) { _useRequestReplyQueues = true; _replySubscriptions = subscriptions; _producers = configuration.ProducerRegistry; _messageMapperRegistry = configuration.MessageMapperRegistry; _outboxWriteTimeout = configuration.OutboxWriteTimeout; _responseChannelFactory = configuration.ResponseChannelFactory; _outbox = outbox; return(this); }
/// <summary> /// Simplified constructor - we /// </summary> /// <param name="outbox">The outbox</param> /// <param name="producer">Producer</param> public BrighterMessaging(IAmAnOutbox <Message> outbox, IAmAMessageProducer producer) { OutBox = outbox; if (outbox is IAmAnOutboxAsync <Message> outboxAsync) { AsyncOutBox = outboxAsync; } Producer = producer; if (producer is IAmAMessageProducerAsync producerAsync) { AsyncProducer = producerAsync; } }
/// <summary> /// The <see cref="CommandProcessor"/> wants to support <see cref="CommandProcessor.Call{T}(T)"/> using RPC between client and server /// </summary> /// <param name="messagingConfiguration"></param> /// <returns></returns> public INeedARequestContext RequestReplyQueues(MessagingConfiguration configuration) { _useRequestReplyQueues = true; _messageStore = configuration.OutBox; _asyncOutbox = configuration.OutboxAsync; _messagingGateway = configuration.MessageProducer; _asyncMessagingGateway = configuration.MessageProducerAsync; _messageMapperRegistry = configuration.MessageMapperRegistry; _messageStoreWriteTimeout = configuration.MessageStoreWriteTimeout; _messagingGatewaySendTimeout = configuration.MessagingGatewaySendTimeout; _responseChannelFactory = configuration.ResponseChannelFactory; return(this); }
/// <summary> /// Simplified constructor - we /// </summary> /// <param name="outbox">The outbox</param> /// <param name="producer">Producer</param> /// <param name="useRequestReplyQueues">Use Request Reply Queues - This will need to set a Channel Factory as well.</param> public BrighterMessaging(IAmAnOutbox <Message> outbox, IAmAMessageProducer producer, bool useRequestReplyQueues = true) { OutBox = outbox; if (outbox is IAmAnOutboxAsync <Message> outboxAsync) { AsyncOutBox = outboxAsync; } Producer = producer; if (producer is IAmAMessageProducerAsync producerAsync) { AsyncProducer = producerAsync; } UseRequestReplyQueues = useRequestReplyQueues; }
/// <summary> /// Creates the specified configuration. /// </summary> /// <param name="gateway">The gateway to the control bus to send messages</param> /// <param name="logger">The logger to use</param> /// <param name="messageStore">The message store for outgoing messages to the control bus</param> /// <returns>IAmAControlBusSender.</returns> public IAmAControlBusSender Create(IAmAnOutbox <Message> messageStore, IAmAMessageProducer gateway) { var mapper = new MessageMapperRegistry(new SimpleMessageMapperFactory((_) => new MonitorEventMessageMapper())); mapper.Register <MonitorEvent, MonitorEventMessageMapper>(); return(new ControlBusSender(CommandProcessorBuilder.With() .Handlers(new HandlerConfiguration()) .DefaultPolicy() .TaskQueues(new MessagingConfiguration(messageStore, gateway, mapper)) .RequestContextFactory(new InMemoryRequestContextFactory()) .Build() )); }
/// <summary> /// Gets the selected messages from the store /// </summary> /// <param name="outBox">The store to retrieve from</param> /// <param name="messageIds">The messages to retrieve</param> /// <returns></returns> private static IEnumerable <Message> GetMessagesFromOutBox(IAmAnOutbox <Message> outBox, IReadOnlyCollection <string> messageIds) { IEnumerable <Message> foundMessages = messageIds .Select(messageId => outBox.Get(Guid.Parse(messageId))) .Where(fm => fm != null) .ToList(); if (foundMessages.Count() < messageIds.Count) { throw new IndexOutOfRangeException("Cannot find messages " + string.Join(",", messageIds.Where(id => foundMessages.All(fm => fm.Id.ToString() != id.ToString())).ToArray())); } return(foundMessages); }
/// <summary> /// Creates the specified configuration. /// </summary> /// <param name="logger">The logger to use</param> /// <param name="outbox">The outbox for outgoing messages to the control bus</param> /// <returns>IAmAControlBusSender.</returns> public IAmAControlBusSender Create(IAmAnOutbox <Message> outbox, IAmAProducerRegistry producerRegistry) { var mapper = new MessageMapperRegistry(new SimpleMessageMapperFactory((_) => new MonitorEventMessageMapper())); mapper.Register <MonitorEvent, MonitorEventMessageMapper>(); return(new ControlBusSender(CommandProcessorBuilder.With() .Handlers(new HandlerConfiguration()) .DefaultPolicy() .ExternalBus(new ExternalBusConfiguration(producerRegistry, mapper), outbox) .RequestContextFactory(new InMemoryRequestContextFactory()) .Build() )); }
/// <summary> /// The <see cref="CommandProcessor"/> wants to support <see cref="CommandProcessor.Post{T}(T)"/> or <see cref="CommandProcessor.Repost"/> using Task Queues. /// You need to provide a policy to specify how QoS issues, specifically <see cref="CommandProcessor.RETRYPOLICY "/> or <see cref="CommandProcessor.CIRCUITBREAKER "/> /// are handled by adding appropriate <see cref="Policies"/> when choosing this option. /// /// </summary> /// <param name="configuration">The Task Queues configuration.</param> /// <returns>INeedARequestContext.</returns> public INeedARequestContext TaskQueues(MessagingConfiguration configuration, IAmAnOutbox <Message> outbox) { _useTaskQueues = true; _messagingGateway = configuration.MessageProducer; _outbox = outbox; if (outbox is IAmAnOutboxAsync <Message> ) { _asyncOutbox = (IAmAnOutboxAsync <Message>)outbox; } _asyncMessagingGateway = configuration.MessageProducerAsync; _messageMapperRegistry = configuration.MessageMapperRegistry; _outboxWriteTimeout = configuration.OutboxWriteTimeout; _messagingGatewaySendTimeout = configuration.MessagingGatewaySendTimeout; return(this); }
/// <summary> /// Initializes a new instance of the <see cref="MessagingConfiguration"/> class. /// </summary> /// <param name="outBox">The outBox.</param> /// <param name="messageProducer">The messaging gateway.</param> /// <param name="messageMapperRegistry">The message mapper registry.</param> /// <param name="messageStoreWriteTimeout">How long to wait when writing to the message store</param> /// <param name="messagingGatewaySendTimeout">How long to wait when sending via the gateway</param> public MessagingConfiguration( IAmAnOutbox <Message> outBox, IAmAMessageProducer messageProducer, IAmAMessageMapperRegistry messageMapperRegistry, int messageStoreWriteTimeout = 300, int messagingGatewaySendTimeout = 300, IAmAChannelFactory responseChannelFactory = null ) { OutBox = outBox; MessageProducer = messageProducer; MessageMapperRegistry = messageMapperRegistry; MessageStoreWriteTimeout = messageStoreWriteTimeout; MessagingGatewaySendTimeout = messagingGatewaySendTimeout; ResponseChannelFactory = responseChannelFactory; }
/// <summary> /// Initializes a new instance of the <see cref="CommandProcessor"/> class. /// Use this constructor when only task queue support is required /// </summary> /// <param name="requestContextFactory">The request context factory.</param> /// <param name="policyRegistry">The policy registry.</param> /// <param name="mapperRegistry">The mapper registry.</param> /// <param name="outBox">The outbox.</param> /// <param name="messageProducer">The messaging gateway.</param> /// <param name="messageStoreTimeout">How long should we wait to write to the message store</param> /// <param name="featureSwitchRegistry">The feature switch config provider.</param> public CommandProcessor( IAmARequestContextFactory requestContextFactory, IPolicyRegistry <string> policyRegistry, IAmAMessageMapperRegistry mapperRegistry, IAmAnOutbox <Message> outBox, IAmAMessageProducer messageProducer, int messageStoreTimeout = 300, IAmAFeatureSwitchRegistry featureSwitchRegistry = null) { _requestContextFactory = requestContextFactory; _policyRegistry = policyRegistry; _messageStoreTimeout = messageStoreTimeout; _mapperRegistry = mapperRegistry; _outBox = outBox; _messageProducer = messageProducer; _featureSwitchRegistry = featureSwitchRegistry; }
/// <summary> /// Initializes a new instance of the <see cref="MessagingConfiguration"/> class. /// </summary> /// <param name="outBox">The OutBox.</param> /// <param name="asyncOutbox">The OutBox that supports async/await.</param> /// <param name="messageProducer">The messaging gateway.</param> /// <param name="asyncmessageProducer">The messaging gateway that supports async/await.</param> /// <param name="messageMapperRegistry">The message mapper registry.</param> /// <param name="messageStoreWriteTimeout">How long to wait when writing to the message store</param> /// <param name="messagingGatewaySendTimeout">How long to wait when sending via the gateway</param> public MessagingConfiguration( IAmAnOutbox <Message> outBox, IAmAnOutboxAsync <Message> asyncOutbox, IAmAMessageProducer messageProducer, IAmAMessageProducerAsync asyncmessageProducer, IAmAMessageMapperRegistry messageMapperRegistry, int messageStoreWriteTimeout = 300, int messagingGatewaySendTimeout = 300 ) { OutBox = outBox; AsyncOutbox = asyncOutbox; MessageProducer = messageProducer; AsyncMessageProducer = asyncmessageProducer; MessageMapperRegistry = messageMapperRegistry; MessageStoreWriteTimeout = messageStoreWriteTimeout; MessagingGatewaySendTimeout = messagingGatewaySendTimeout; }
/// <summary> /// Initializes a new instance of the <see cref="MessagingConfiguration"/> class. /// </summary> /// <param name="outBox">The OutBox.</param> /// <param name="outboxAsync">The OutBox that supports async/await.</param> /// <param name="messageProducer">The messaging gateway.</param> /// <param name="asyncmessageProducer">The messaging gateway that supports async/await.</param> /// <param name="messageMapperRegistry">The message mapper registry.</param> /// <param name="outboxWriteTimeout">How long to wait when writing to the outbox</param> /// <param name="messagingGatewaySendTimeout">How long to wait when sending via the gateway</param> /// <param name="useInbox">Do we want to create an inbox globally i.e. on every handler (as opposed to by hand). Defaults to null, by hand</param> public MessagingConfiguration( IAmAnOutbox <Message> outBox, IAmAnOutboxAsync <Message> outboxAsync, IAmAMessageProducer messageProducer, IAmAMessageProducerAsync asyncmessageProducer, IAmAMessageMapperRegistry messageMapperRegistry, int outboxWriteTimeout = 300, int messagingGatewaySendTimeout = 300, InboxConfiguration useInbox = null ) { OutBox = outBox; OutboxAsync = outboxAsync; MessageProducer = messageProducer; MessageProducerAsync = asyncmessageProducer; MessageMapperRegistry = messageMapperRegistry; OutboxWriteTimeout = outboxWriteTimeout; MessagingGatewaySendTimeout = messagingGatewaySendTimeout; UseInbox = useInbox; }
/// <summary> /// Initializes a new instance of the <see cref="CommandProcessor"/> class. /// Use this constructor when both task queue and command processor support is required, and you want to inject a test logger /// </summary> /// <param name="subscriberRegistry">The subscriber registry.</param> /// <param name="handlerFactory">The handler factory.</param> /// <param name="asyncHandlerFactory">The async handler factory.</param> /// <param name="requestContextFactory">The request context factory.</param> /// <param name="policyRegistry">The policy registry.</param> /// <param name="mapperRegistry">The mapper registry.</param> /// <param name="outBox">The outbox.</param> /// <param name="asyncOutbox">The message store supporting async/await.</param> /// <param name="messageProducer">The messaging gateway.</param> /// <param name="asyncMessageProducer">The messaging gateway supporting async/await.</param> /// <param name="messageStoreTimeout">How long should we wait to write to the message store</param> /// <param name="featureSwitchRegistry">The feature switch config provider.</param> public CommandProcessor( IAmASubscriberRegistry subscriberRegistry, IAmAHandlerFactory handlerFactory, IAmAHandlerFactoryAsync asyncHandlerFactory, IAmARequestContextFactory requestContextFactory, IPolicyRegistry <string> policyRegistry, IAmAMessageMapperRegistry mapperRegistry, IAmAnOutbox <Message> outBox, IAmAnOutboxAsync <Message> asyncOutbox, IAmAMessageProducer messageProducer, IAmAMessageProducerAsync asyncMessageProducer, int messageStoreTimeout = 300, IAmAFeatureSwitchRegistry featureSwitchRegistry = null) : this(subscriberRegistry, handlerFactory, asyncHandlerFactory, requestContextFactory, policyRegistry, featureSwitchRegistry) { _mapperRegistry = mapperRegistry; _outBox = outBox; _asyncOutbox = asyncOutbox; _messageProducer = messageProducer; _asyncMessageProducer = asyncMessageProducer; _messageStoreTimeout = messageStoreTimeout; }
/// <summary> /// Initializes a new instance of the <see cref="CommandProcessor"/> class. /// Use this constructor when only posting messages to an external bus is required /// </summary> /// <param name="requestContextFactory">The request context factory.</param> /// <param name="policyRegistry">The policy registry.</param> /// <param name="mapperRegistry">The mapper registry.</param> /// <param name="outBox">The outbox</param> /// <param name="producerRegistry">The register of producers via whom we send messages over the external bus</param> /// <param name="outboxTimeout">How long should we wait to write to the outbox</param> /// <param name="featureSwitchRegistry">The feature switch config provider.</param> /// <param name="inboxConfiguration">Do we want to insert an inbox handler into pipelines without the attribute. Null (default = no), yes = how to configure</param> /// <param name="boxTransactionConnectionProvider">The Box Connection Provider to use when Depositing into the outbox.</param> public CommandProcessor( IAmARequestContextFactory requestContextFactory, IPolicyRegistry <string> policyRegistry, IAmAMessageMapperRegistry mapperRegistry, IAmAnOutbox <Message> outBox, IAmAProducerRegistry producerRegistry, int outboxTimeout = 300, IAmAFeatureSwitchRegistry featureSwitchRegistry = null, InboxConfiguration inboxConfiguration = null, IAmABoxTransactionConnectionProvider boxTransactionConnectionProvider = null) { _requestContextFactory = requestContextFactory; _policyRegistry = policyRegistry; _mapperRegistry = mapperRegistry; _featureSwitchRegistry = featureSwitchRegistry; _inboxConfiguration = inboxConfiguration; _boxTransactionConnectionProvider = boxTransactionConnectionProvider; InitExtServiceBus(policyRegistry, outBox, outboxTimeout, producerRegistry); ConfigureCallbacks(producerRegistry); }
/// <summary> /// Use an external Brighter Outbox to store messages Posted to another process (evicts based on age and size). /// Advantages: By using the same Db to store both any state changes for your app, and outgoing messages you can create a transaction that spans both /// your state change and writing to an outbox [use DepositPost to store]. Then a sweeper process can look for message not flagged as sent and send them. /// For low latency just send after the transaction with ClearOutbox, for higher latency just let the sweeper run in the background. /// The outstanding messages dispatched this way can be sent from any producer that runs a sweeper process and so it not tied to the lifetime of the /// producer, offering guaranteed, at least once, delivery. /// NOTE: there may be a database specific Use*OutBox available. If so, use that in preference to this generic method /// If not null, registers singletons with the service collection :- /// - IAmAnOutboxSync - what messages have we posted /// - ImAnOutboxAsync - what messages have we posted (async pipeline compatible) /// </summary> /// <param name="brighterBuilder">The Brighter builder to add this option to</param> /// <param name="outbox">The outbox provider - if your outbox supports both sync and async options, just provide this and we will register both</param> /// <returns></returns> public static IBrighterBuilder UseExternalOutbox(this IBrighterBuilder brighterBuilder, IAmAnOutbox <Message> outbox = null) { if (outbox is IAmAnOutboxSync <Message> ) { brighterBuilder.Services.Add(new ServiceDescriptor(typeof(IAmAnOutboxSync <Message>), _ => outbox, ServiceLifetime.Singleton)); } if (outbox is IAmAnOutboxAsync <Message> ) { brighterBuilder.Services.Add(new ServiceDescriptor(typeof(IAmAnOutboxAsync <Message>), _ => outbox, ServiceLifetime.Singleton)); } return(brighterBuilder); }