/// <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); }
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); }
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); }
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); }
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); }
/// <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); }
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); }
/// <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); }
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); } }
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); }); }); }
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); }
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); }); }); }
public void ApplyExchangeSettings(ExchangeMeta meta) { ApplyExchangeSettingsInternal(meta); }
protected override IRpcClient CreateRpcClient(ExchangeMeta definition) { Mock <IRpcClient> mockRpcClient = new Mock <IRpcClient>(); return(mockRpcClient.Object); }
private static async Task <CreatedExchange> CreateExchange(IBus bus, ExchangeMeta meta) { IExchange exchange = await bus.Advanced.ExchangeDeclareAsync(meta); return(new CreatedExchange(bus, exchange, meta)); }