예제 #1
0
        /// <summary>
        /// Implements RPC over an asynchronous message bus.  While the publisher does not block
        /// and can complete other unrelated work, the publisher is synchronous in terms that they
        /// can't complete their entire work until the response is received.
        /// </summary>
        /// <param name="queueName">The name of the queue on which the subscriber will receive commands.</param>
        /// <param name="actionNamespace">For a given RPC command, identifies to the consumer the associated action.</param>
        /// <param name="busName">The bus name key used to lookup connection.</param>
        /// <param name="settings">Optional delegate called allowing caller to set
        /// additional exchange properties.</param>
        /// <typeparam name="TMessage">The command type associated with the queue.</typeparam>
        protected void DefineRpcQueue <TMessage>(string queueName, string actionNamespace, string busName,
                                                 Action <ExchangeMeta <TMessage> > settings = null)
            where TMessage : ICommand
        {
            if (string.IsNullOrWhiteSpace(actionNamespace))
            {
                throw new ArgumentException("RPC Action Namespace not Specified.", nameof(actionNamespace));
            }

            var publisherStrategy = new RpcPublisherStrategy();

            var exchange = ExchangeMeta.DefineDefault <TMessage>(busName, queueName,
                                                                 config =>
            {
                config.IsAutoDelete = true;
                config.IsDurable    = false;
                config.IsPassive    = false;
                config.IsExclusive  = false;
            });

            exchange.IsAutoDelete    = true;
            exchange.IsRpcExchange   = true;
            exchange.ActionNamespace = actionNamespace;
            exchange.SetPublisherStrategy(publisherStrategy);

            _exchanges.Add(exchange);
            settings?.Invoke(exchange);
        }
예제 #2
0
        public override async Task PublishMessageAsync(IMessage message, CancellationToken cancellationToken)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            // Only process messages for which there are defined exchanges.
            Type messageType = message.GetType();

            if (!PublisherModule.IsExchangeMessage(messageType))
            {
                return;
            }

            // Lookup the exchange associated with the message and the bus
            // on which it should be created.
            ExchangeMeta definition = PublisherModule.GetDefinition(messageType);
            IBus         bus        = BusModule.GetBus(definition.BusName);

            // Create the exchange/queue:
            CreatedExchange createdExchange = await CreateExchange(bus, definition).ConfigureAwait(false);

            LogPublishedMessage(createdExchange, message);

            // Publish the message to the created exchange/queue.
            await definition.PublisherStrategy.Publish(this, createdExchange,
                                                       message,
                                                       cancellationToken);
        }
예제 #3
0
        protected virtual IRpcClient CreateRpcClient(ExchangeMeta definition)
        {
            IBus bus       = BusModule.GetBus(definition.BusName);
            var  rpcClient = new RpcClient(definition.BusName, definition.QueueMeta.QueueName, bus);
            var  logger    = Context.LoggerFactory.CreateLogger <RpcClient>();

            rpcClient.SetLogger(logger);
            return(rpcClient);
        }
예제 #4
0
 public CreatedExchange(
     IBus bus,
     IExchange exchange,
     ExchangeMeta definition)
 {
     Bus        = bus ?? throw new System.ArgumentNullException(nameof(bus));
     Exchange   = exchange ?? throw new System.ArgumentNullException(nameof(exchange));
     Definition = definition ?? throw new System.ArgumentNullException(nameof(definition));
 }
        private static async Task <bool> Satisfies(IPublisherContext context, CreatedExchange createdExchange, IMessage message)
        {
            ExchangeMeta definition = createdExchange.Definition;
            bool         applies    = definition.Applies(message);

            if (applies && definition.ScriptPredicate != null)
            {
                return(await context.Scripting.SatisfiesPredicateAsync(message, definition.ScriptPredicate));
            }

            return(applies);
        }
예제 #6
0
        public QueueMeta CreateQueueMeta(SubscriberQueueAttribute attribute)
        {
            var exchange = ExchangeMeta.DefineDefault(attribute.BusName, attribute.QueueName,
                                                      config =>
            {
                config.IsAutoDelete = false;
                config.IsDurable    = true;
                config.IsPassive    = false;
                config.IsExclusive  = false;
            });

            return(exchange.QueueMeta);
        }
예제 #7
0
        /// <summary>
        /// Defines a fanout exchange that will broadcast messages to all bound message queues.
        /// This should be used for notification type messages where the subscriber only cares
        /// about current occurring messages and not about prior missed messages that happened
        /// when they were offline.
        ///
        /// https://www.rabbitmq.com/tutorials/amqp-concepts.html#exchange-fanout
        /// </summary>
        /// <param name="name">The name of the exchange.</param>
        /// <param name="busName">The bus name key used to lookup connection.</param>
        /// <param name="settings">Optional delegate called allowing caller to set
        /// additional exchange properties.</param>
        /// <typeparam name="TMessage">The domain-event type associated with the exchange.</typeparam>
        protected void DefineFanoutExchange <TMessage>(string name, string busName,
                                                       Action <ExchangeMeta <TMessage> > settings = null)
            where TMessage : IDomainEvent
        {
            var exchange = ExchangeMeta.Define <TMessage>(busName, name, ExchangeType.Fanout,
                                                          config =>
            {
                config.IsAutoDelete = true;
                config.IsDurable    = false;
                config.IsPersistent = false;
                config.IsPassive    = false;
            });

            _exchanges.Add(exchange);
            settings?.Invoke(exchange);
        }
예제 #8
0
        public QueueMeta CreateQueueMeta(SubscriberQueueAttribute attribute)
        {
            var rpcAttribute = (RpcQueueAttribute)attribute;

            var exchange = ExchangeMeta.DefineDefault(rpcAttribute.BusName, rpcAttribute.QueueName,
                                                      config =>
            {
                config.IsAutoDelete = true;
                config.IsDurable    = false;
                config.IsPassive    = false;
                config.IsExclusive  = false;
            });

            exchange.IsRpcExchange   = true;
            exchange.ActionNamespace = rpcAttribute.ActionNamespace;
            return(exchange.QueueMeta);
        }
예제 #9
0
        /// <summary>
        /// Defines a work queue.  For the other type of exchanges, the publisher does not know
        /// the consumers subscribing to the queues defined on the exchange.  A work queue is used
        /// to make a request of another service by sending a command to the queue for processing.
        /// The processing is asynchronous and the publisher does not wait for a response.  This
        /// should be used by a publisher to submit a time consuming task to a specific service
        /// for processing.
        /// </summary>
        /// <param name="queueName">The name of the queue on which the consuming service will receive commands.</param>
        /// <param name="busName">The bus name key used to lookup connection.</param>
        /// <param name="settings">Optional delegate called allowing caller to set
        /// additional exchange properties.</param>
        /// <typeparam name="TMessage">The command type associated with the queue.</typeparam>
        protected void DefineWorkQueue <TMessage>(string queueName, string busName,
                                                  Action <ExchangeMeta <TMessage> > settings = null)
            where TMessage : ICommand
        {
            var exchange = ExchangeMeta.DefineDefault <TMessage>(busName, queueName,
                                                                 config =>
            {
                config.IsAutoDelete = false;
                config.IsDurable    = true;
                config.IsPassive    = false;
                config.IsExclusive  = false;
            });

            exchange.RouteKey = queueName;

            _exchanges.Add(exchange);
            settings?.Invoke(exchange);
        }
예제 #10
0
        private void ApplyExchangeSettingsInternal(ExchangeMeta meta, bool applyQueueSettings = true)
        {
            if (meta == null)
            {
                throw new ArgumentNullException(nameof(meta));
            }

            if (!meta.IsDefaultExchange)
            {
                var exchangeSettings = GetExchangeSettings(meta.BusName, meta.ExchangeName);
                if (exchangeSettings != null)
                {
                    meta.ApplyOverrides(exchangeSettings);
                }
            }

            if (applyQueueSettings && meta.QueueMeta != null)
            {
                ApplyQueueSettings(meta.QueueMeta);
            }
        }
예제 #11
0
        public void CanSpecifyExchangeSettings_InConfiguration()
        {
            ContainerFixture.Test(fixture => {
                fixture.Arrange
                .Configuration(TestSetup.AddValidBusConfigWithExchangeSettings)
                .Container(c =>
                {
                    c.WithRabbitMqHost();
                })
                .Assert.PluginModule <MockBusModule>(m =>
                {
                    var exchangeMeta = ExchangeMeta.Define("TestBus1", "TestExchangeName", ExchangeType.Direct);
                    m.ApplyExchangeSettings(exchangeMeta);

                    Assert.True(exchangeMeta.IsPassive);
                    Assert.Equal("TestAltExchangeName", exchangeMeta.AlternateExchangeName);
                    Assert.Equal("TestContentType", exchangeMeta.ContentType);
                    Assert.Equal(10000, exchangeMeta.CancelRpcRequestAfterMs);
                });
            });
        }
예제 #12
0
        public QueueMeta CreateQueueMeta(SubscriberQueueAttribute attribute)
        {
            var exchange = ExchangeMeta.Define(attribute.BusName, attribute.ExchangeName, ExchangeType.Fanout,
                                               config =>
            {
                config.IsAutoDelete = true;
                config.IsDurable    = false;
                config.IsPassive    = false;
                config.IsPersistent = false;
            });

            var queue = QueueMeta.Define(attribute.QueueName, exchange,
                                         config =>
            {
                config.IsAutoDelete   = true;
                config.IsDurable      = false;
                config.IsPassive      = false;
                config.IsExclusive    = true;
                config.AppendUniqueId = true;
            });

            return(queue);
        }
예제 #13
0
        public void CanSpecifyQueueSettings_InConfiguration()
        {
            ContainerFixture.Test(fixture => {
                fixture.Arrange
                .Configuration(TestSetup.AddValidBusConfigWithQueueSettings)
                .Container(c =>
                {
                    c.WithRabbitMqHost();
                })
                .Assert.PluginModule <MockBusModule>(m =>
                {
                    var queueMeta = ExchangeMeta.DefineDefault("TestBus1", "TestQueueName").QueueMeta;
                    m.ApplyQueueSettings(queueMeta);

                    Assert.True(queueMeta.IsPassive);
                    Assert.Equal(20000, queueMeta.PerQueueMessageTtl);
                    Assert.Equal("TestDeadLetterExchange", queueMeta.DeadLetterExchange);
                    Assert.Equal("TestDeadLetterRoutingKey", queueMeta.DeadLetterRoutingKey);
                    Assert.Equal((byte)10, queueMeta.MaxPriority);
                    Assert.Equal(5, queueMeta.PrefetchCount);
                    Assert.Equal(2, queueMeta.Priority);
                });
            });
        }
예제 #14
0
 public void ApplyExchangeSettings(ExchangeMeta meta)
 {
     ApplyExchangeSettingsInternal(meta);
 }
예제 #15
0
        protected override IRpcClient CreateRpcClient(ExchangeMeta definition)
        {
            Mock <IRpcClient> mockRpcClient = new Mock <IRpcClient>();

            return(mockRpcClient.Object);
        }
예제 #16
0
        private static async Task <CreatedExchange> CreateExchange(IBus bus, ExchangeMeta meta)
        {
            IExchange exchange = await bus.Advanced.ExchangeDeclareAsync(meta);

            return(new CreatedExchange(bus, exchange, meta));
        }