예제 #1
0
        // -------------------------------- publish ---------------------------------------------

        public virtual Task PublishAsync(
            IExchange exchange,
            string routingKey,
            bool mandatory,
            bool immediate,
            MessageProperties messageProperties,
            byte[] body)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(messageProperties, "messageProperties");
            Preconditions.CheckNotNull(body, "body");

            var task = clientCommandDispatcher.Invoke(x =>
            {
                var properties = x.CreateBasicProperties();
                messageProperties.CopyTo(properties);

                return(_publisher.Publish(x,
                                          m => m.BasicPublish(exchange.Name, routingKey, mandatory, immediate, properties, body)));
            }).Unwrap();

            logger.DebugWrite("Published to exchange: '{0}', routing key: '{1}', correlationId: '{2}'",
                              exchange.Name, routingKey, messageProperties.CorrelationId);

            return(task);
        }
예제 #2
0
        public virtual Task PublishAsync(
            IExchange exchange,
            string routingKey,
            bool mandatory,
            bool immediate,
            MessageProperties messageProperties,
            byte[] body)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(messageProperties, "messageProperties");
            Preconditions.CheckNotNull(body, "body");

            var rawMessage = produceConsumeInterceptor.OnProduce(new RawMessage(messageProperties, body));

            return(clientCommandDispatcher.InvokeAsync(x =>
            {
                var properties = x.CreateBasicProperties();
                rawMessage.Properties.CopyTo(properties);

                return publisher.PublishAsync(x, m => m.BasicPublish(exchange.Name, routingKey, mandatory, immediate, properties, rawMessage.Body))
                .Then(() =>
                {
                    eventBus.Publish(new PublishedMessageEvent(exchange.Name, routingKey, rawMessage.Properties, rawMessage.Body));
                    logger.DebugWrite("Published to exchange: '{0}', routing key: '{1}', correlationId: '{2}'", exchange.Name, routingKey, messageProperties.CorrelationId);
                });
            }).Unwrap());
        }
예제 #3
0
        public async Task <IExchange> ExchangeDeclareAsync(
            string name,
            string type,
            bool passive             = false,
            bool durable             = true,
            bool autoDelete          = false,
            bool @internal           = false,
            string alternateExchange = null,
            bool delayed             = false)
        {
            Preconditions.CheckShortString(name, "name");
            Preconditions.CheckShortString(type, "type");

            if (passive)
            {
                await clientCommandDispatcher.InvokeAsync(x => x.ExchangeDeclarePassive(name)).ConfigureAwait(false);

                return(new Exchange(name));
            }
            IDictionary <string, object> arguments = new Dictionary <string, object>();

            if (alternateExchange != null)
            {
                arguments.Add("alternate-exchange", alternateExchange);
            }
            if (delayed)
            {
                arguments.Add("x-delayed-type", type);
                type = "x-delayed-message";
            }
            await clientCommandDispatcher.InvokeAsync(x => x.ExchangeDeclare(name, type, durable, autoDelete, arguments)).ConfigureAwait(false);

            logger.DebugWrite("Declared Exchange: {0} type:{1}, durable:{2}, autoDelete:{3}, delayed:{4}", name, type, durable, autoDelete, delayed);
            return(new Exchange(name));
        }
예제 #4
0
        public virtual IExchange ExchangeDeclare(
            string name,
            string type,
            bool passive             = false,
            bool durable             = true,
            bool autoDelete          = false,
            bool @internal           = false,
            string alternateExchange = null)
        {
            Preconditions.CheckNotNull(name, "name");
            Preconditions.CheckShortString(type, "type");

            if (passive)
            {
                clientCommandDispatcher.Invoke(x => x.ExchangeDeclarePassive(name)).Wait();
            }
            else
            {
                IDictionary arguments = null;
                if (alternateExchange != null)
                {
                    arguments = new Hashtable {
                        { "alternate-exchange", alternateExchange }
                    };
                }

                clientCommandDispatcher.Invoke(x => x.ExchangeDeclare(name, type, durable, autoDelete, arguments)).Wait();
                logger.DebugWrite("Declared Exchange: {0} type:{1}, durable:{2}, autoDelete:{3}",
                                  name, type, durable, autoDelete);
            }

            return(new Exchange(name));
        }
예제 #5
0
        public virtual IBinding Bind(IExchange exchange, IQueue queue, string routingKey)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckNotNull(queue, "queue");
            Preconditions.CheckShortString(routingKey, "routingKey");

            clientCommandDispatcher.Invoke(x => x.QueueBind(queue.Name, exchange.Name, routingKey));
            logger.DebugWrite("Bound queue {0} to exchange {1} with routing key {2}", queue.Name, exchange.Name, routingKey);
            return(new Binding(queue, exchange, routingKey));
        }
예제 #6
0
        public virtual IBinding Bind(IExchange source, IExchange destination, string routingKey)
        {
            Preconditions.CheckNotNull(source, "source");
            Preconditions.CheckNotNull(destination, "destination");
            Preconditions.CheckShortString(routingKey, "routingKey");

            clientCommandDispatcher.Invoke(x => x.ExchangeBind(destination.Name, source.Name, routingKey));
            logger.DebugWrite("Bound destination exchange {0} to source exchange {1} with routing key {2}", destination.Name, source.Name, routingKey);
            return(new Binding(destination, source, routingKey));
        }
예제 #7
0
        public async Task <IBinding> BindAsync(IExchange source, IExchange destination, string routingKey)
        {
            Preconditions.CheckNotNull(source, "source");
            Preconditions.CheckNotNull(destination, "destination");
            Preconditions.CheckShortString(routingKey, "routingKey");

            await clientCommandDispatcher.InvokeAsync(x => x.ExchangeBind(destination.Name, source.Name, routingKey)).ConfigureAwait(false);

            logger.DebugWrite("Bound destination exchange {0} to source exchange {1} with routing key {2}", destination.Name, source.Name, routingKey);
            return((IBinding) new Binding(destination, source, routingKey));
        }
예제 #8
0
        public async Task <IBinding> BindAsync(IExchange exchange, IQueue queue, string routingKey)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckNotNull(queue, "queue");
            Preconditions.CheckShortString(routingKey, "routingKey");

            await clientCommandDispatcher.InvokeAsync(x => x.QueueBind(queue.Name, exchange.Name, routingKey)).ConfigureAwait(false);

            logger.DebugWrite("Bound queue {0} to exchange {1} with routing key {2}", queue.Name, exchange.Name, routingKey);
            return((IBinding) new Binding(queue, exchange, routingKey));
        }
예제 #9
0
        public virtual IBinding Bind(IExchange exchange, IQueue queue, string routingKey, IDictionary <string, object> headers)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(queue, "headers");

            var arguments = headers ?? new Dictionary <string, object>();

            clientCommandDispatcher.Invoke(x => x.QueueBind(queue.Name, exchange.Name, routingKey, arguments));
            logger.DebugWrite("Bound queue {0} to exchange {1} with routing key {2} and {3} arguments", queue.Name, exchange.Name, routingKey, arguments.Count);
            return(new Binding(queue, exchange, routingKey, arguments));
        }
예제 #10
0
        public async Task <IExchange> ExchangeDeclareAsync(
            string name,
            string type,
            bool passive             = false,
            bool durable             = true,
            bool autoDelete          = false,
            bool @internal           = false,
            string alternateExchange = null,
            bool delayed             = false,
            IDictionary <string, object> arguments = null)
        {
            Preconditions.CheckShortString(name, "name");
            Preconditions.CheckShortString(type, "type");

            if (passive)
            {
                await clientCommandDispatcher.InvokeAsync(x => x.ExchangeDeclarePassive(name)).ConfigureAwait(false);

                return(new Exchange(name));
            }

            if (arguments == null)
            {
                arguments = new Dictionary <string, object>();
            }

            if (alternateExchange != null)
            {
                arguments["alternate-exchange"] = alternateExchange;
            }

            if (delayed)
            {
                arguments["x-delayed-type"] = type;
                type = "x-delayed-message";
            }

            await clientCommandDispatcher.InvokeAsync(x => x.ExchangeDeclare(name, type, durable, autoDelete, arguments)).ConfigureAwait(false);

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat(
                    "Declared exchange {exchange}: type={type}, durable={durable}, autoDelete={autoDelete}, arguments={arguments}",
                    name,
                    type,
                    durable,
                    autoDelete,
                    arguments.Stringify()
                    );
            }

            return(new Exchange(name));
        }
예제 #11
0
        public async Task <IBinding> BindAsync(IExchange source, IExchange destination, string routingKey, IDictionary <string, object> headers)
        {
            Preconditions.CheckNotNull(source, "source");
            Preconditions.CheckNotNull(destination, "destination");
            Preconditions.CheckShortString(routingKey, "routingKey");

            var arguments = headers ?? new Dictionary <string, object>();
            await clientCommandDispatcher.InvokeAsync(x => x.ExchangeBind(destination.Name, source.Name, routingKey, arguments)).ConfigureAwait(false);

            logger.DebugWrite("Bound destination exchange {0} to source exchange {1} with routing key {2} and {3} arguments", destination.Name, source.Name, routingKey, arguments.Count);
            return(new Binding(destination, source, routingKey, arguments));
        }
예제 #12
0
        public async Task <IBinding> BindAsync(IExchange exchange, IQueue queue, string routingKey, IDictionary <string, object> headers)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckNotNull(queue, "queue");
            Preconditions.CheckShortString(routingKey, "routingKey");

            var arguments = headers ?? new Dictionary <string, object>();
            await clientCommandDispatcher.InvokeAsync(x => x.QueueBind(queue.Name, exchange.Name, routingKey, arguments)).ConfigureAwait(false);

            logger.DebugWrite("Bound queue {0} to exchange {1} with routing key {2} and {3} arguments", queue.Name, exchange.Name, routingKey, arguments.Count);
            return(new Binding(queue, exchange, routingKey, arguments));
        }
예제 #13
0
        /// <inheritdoc />
        public virtual AwaitableDisposable <IDisposable> RespondAsync <TRequest, TResponse>(
            Func <TRequest, CancellationToken, Task <TResponse> > responder,
            Action <IResponderConfiguration> configure,
            CancellationToken cancellationToken = default
            )
        {
            Preconditions.CheckNotNull(responder, "responder");
            Preconditions.CheckNotNull(configure, "configure");
            // We're explicitly validating TResponse here because the type won't be used directly.
            // It'll only be used when executing a successful responder, which will silently fail if TResponse serialized length exceeds the limit.
            Preconditions.CheckShortString(typeNameSerializer.Serialize(typeof(TResponse)), "TResponse");

            return(RespondAsyncInternal(responder, configure, cancellationToken).ToAwaitableDisposable());
        }
예제 #14
0
        public virtual Task PublishAsync <T>(
            IExchange exchange,
            string routingKey,
            bool mandatory,
            IMessage <T> message) where T : class
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(message, "message");

            var serializedMessage = messageSerializationStrategy.SerializeMessage(message);

            return(PublishAsync(exchange, routingKey, mandatory, serializedMessage.Properties, serializedMessage.Body));
        }
예제 #15
0
        /// <inheritdoc />
        public async Task ExchangeDeclarePassiveAsync(string name, CancellationToken cancellationToken = default)
        {
            Preconditions.CheckShortString(name, "name");

            using var cts = cancellationToken.WithTimeout(configuration.Timeout);

            await clientCommandDispatcher.InvokeAsync(
                x => x.ExchangeDeclarePassive(name), cts.Token
                ).ConfigureAwait(false);

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat("Passive declared exchange {exchange}", name);
            }
        }
예제 #16
0
        public virtual IExchange ExchangeDeclare(
            string name,
            string type,
            bool passive             = false,
            bool durable             = true,
            bool autoDelete          = false,
            bool @internal           = false,
            string alternateExchange = null,
            bool delayed             = false)
        {
            Preconditions.CheckShortString(name, "name");
            Preconditions.CheckShortString(type, "type");

            if (passive)
            {
                clientCommandDispatcher.Invoke(x => x.ExchangeDeclarePassive(name));
                return(new Exchange(name));
            }

            IDictionary <string, object> arguments = new Dictionary <string, object>();

            if (alternateExchange != null)
            {
                arguments.Add("alternate-exchange", alternateExchange);
            }

            if (delayed)
            {
                arguments.Add("x-delayed-type", type);
                type = "x-delayed-message";
            }

            clientCommandDispatcher.Invoke(x => x.ExchangeDeclare(name, type, durable, autoDelete, arguments));

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat(
                    "Declared exchange {exchange}: type={type}, durable={durable}, autoDelete={autoDelete}, arguments={arguments}",
                    name,
                    type,
                    durable,
                    autoDelete,
                    arguments.Stringify()
                    );
            }

            return(new Exchange(name));
        }
예제 #17
0
        public async Task <IBinding> BindAsync(IExchange source, IExchange destination, string routingKey, IDictionary <string, object> headers)
        {
            Preconditions.CheckNotNull(source, "source");
            Preconditions.CheckNotNull(destination, "destination");
            Preconditions.CheckShortString(routingKey, "routingKey");

            var arguments = headers ?? new Dictionary <string, object>();
            await clientCommandDispatcher.InvokeAsync(x => x.ExchangeBind(destination.Name, source.Name, routingKey, arguments)).ConfigureAwait(false);

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat(
                    "Bound destination exchange {destinationExchange} to source exchange {sourceExchange} with routingKey={routingKey} and arguments={arguments}",
                    destination.Name,
                    source.Name,
                    routingKey,
                    arguments.Stringify()
                    );
            }

            return(new Binding(destination, source, routingKey, arguments));
        }
예제 #18
0
        public async Task <IBinding> BindAsync(IExchange exchange, IQueue queue, string routingKey, IDictionary <string, object> headers)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckNotNull(queue, "queue");
            Preconditions.CheckShortString(routingKey, "routingKey");

            var arguments = headers ?? new Dictionary <string, object>();
            await clientCommandDispatcher.InvokeAsync(x => x.QueueBind(queue.Name, exchange.Name, routingKey, arguments)).ConfigureAwait(false);

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat(
                    "Bound queue {queue} to exchange {exchange} with routingKey={routingKey} and arguments={arguments}",
                    queue.Name,
                    exchange.Name,
                    routingKey,
                    arguments.Stringify()
                    );
            }

            return(new Binding(queue, exchange, routingKey, arguments));
        }
예제 #19
0
        public virtual Task PublishAsync <T>(
            IExchange exchange,
            string routingKey,
            bool mandatory,
            bool immediate,
            IMessage <T> message) where T : class
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(message, "message");

            var typeName    = typeNameSerializer.Serialize(message.Body.GetType());
            var messageBody = serializer.MessageToBytes(message.Body);

            message.Properties.Type          = typeName;
            message.Properties.CorrelationId =
                string.IsNullOrEmpty(message.Properties.CorrelationId) ?
                getCorrelationId() :
                message.Properties.CorrelationId;

            return(PublishAsync(exchange, routingKey, mandatory, immediate, message.Properties, messageBody));
        }
예제 #20
0
        public virtual IExchange ExchangeDeclare(
            string name,
            string type,
            bool passive    = false,
            bool durable    = true,
            bool autoDelete = false,
            bool @internal  = false)
        {
            Preconditions.CheckNotNull(name, "name");
            Preconditions.CheckShortString(type, "type");

            if (passive)
            {
                clientCommandDispatcher.Invoke(x => x.ExchangeDeclarePassive(name)).Wait();
            }
            else
            {
                clientCommandDispatcher.Invoke(x => x.ExchangeDeclare(name, type, durable, autoDelete, null)).Wait();
                logger.DebugWrite("Declared Exchange: {0} type:{1}, durable:{2}, autoDelete:{3}",
                                  name, type, durable, autoDelete);
            }

            return(new Exchange(name));
        }
예제 #21
0
        /// <inheritdoc />
        public async Task <IExchange> ExchangeDeclareAsync(
            string name,
            Action <IExchangeDeclareConfiguration> configure,
            CancellationToken cancellationToken = default
            )
        {
            Preconditions.CheckShortString(name, "name");

            using var cts = cancellationToken.WithTimeout(configuration.Timeout);

            var exchangeDeclareConfiguration = new ExchangeDeclareConfiguration();

            configure(exchangeDeclareConfiguration);
            var type         = exchangeDeclareConfiguration.Type;
            var isDurable    = exchangeDeclareConfiguration.IsDurable;
            var isAutoDelete = exchangeDeclareConfiguration.IsAutoDelete;
            var arguments    = exchangeDeclareConfiguration.Arguments;

            await clientCommandDispatcher.InvokeAsync(
                x => x.ExchangeDeclare(name, type, isDurable, isAutoDelete, arguments), cts.Token
                ).ConfigureAwait(false);

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat(
                    "Declared exchange {exchange}: type={type}, durable={durable}, autoDelete={autoDelete}, arguments={arguments}",
                    name,
                    type,
                    isDurable,
                    isAutoDelete,
                    arguments.Stringify()
                    );
            }

            return(new Exchange(name, type, isDurable, isAutoDelete, arguments));
        }
예제 #22
0
        public Task <IExchange> ExchangeDeclareAsync(
            string name,
            string type,
            bool passive             = false,
            bool durable             = true,
            bool autoDelete          = false,
            bool @internal           = false,
            string alternateExchange = null)
        {
            Preconditions.CheckShortString(name, "name");
            Preconditions.CheckShortString(type, "type");

            if (passive)
            {
                return(clientCommandDispatcher.Invoke(x => x.ExchangeDeclarePassive(name))
                       .Then(() => (IExchange) new Exchange(name)));
            }

            IDictionary <string, object> arguments = null;

            if (alternateExchange != null)
            {
                arguments = new Dictionary <string, object> {
                    { "alternate-exchange", alternateExchange }
                };
            }

            return(clientCommandDispatcher.Invoke(x => x.ExchangeDeclare(name, type, durable, autoDelete, arguments))
                   .Then(() =>
            {
                logger.DebugWrite("Declared Exchange: {0} type:{1}, durable:{2}, autoDelete:{3}",
                                  name, type, durable, autoDelete);

                return (IExchange) new Exchange(name);
            }));
        }
예제 #23
0
        public virtual async Task PublishAsync(
            IExchange exchange,
            string routingKey,
            bool mandatory,
            MessageProperties messageProperties,
            byte[] body)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(messageProperties, "messageProperties");
            Preconditions.CheckNotNull(body, "body");

            // Fix me: It's very hard now to move publish logic to separate abstraction, just leave it here.
            var rawMessage = produceConsumeInterceptor.OnProduce(new RawMessage(messageProperties, body));

            if (connectionConfiguration.PublisherConfirms)
            {
                var timeout = TimeBudget.Start(connectionConfiguration.GetTimeout());
                while (true)
                {
                    if (timeout.IsExpired())
                    {
                        throw new TimeoutException($"Publish timed out after {connectionConfiguration.Timeout} seconds");
                    }

                    var confirmsWaiter = await clientCommandDispatcher.InvokeAsync(model =>
                    {
                        var properties = model.CreateBasicProperties();
                        rawMessage.Properties.CopyTo(properties);
                        var waiter = confirmationListener.GetWaiter(model);

                        try
                        {
                            model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body);
                        }
                        catch (Exception)
                        {
                            waiter.Cancel();
                            throw;
                        }

                        return(waiter);
                    }).ConfigureAwait(false);

                    try
                    {
                        await confirmsWaiter.WaitAsync(timeout).ConfigureAwait(false);

                        break;
                    }
                    catch (PublishInterruptedException)
                    {
                    }
                }
            }
            else
            {
                await clientCommandDispatcher.InvokeAsync(model =>
                {
                    var properties = model.CreateBasicProperties();
                    rawMessage.Properties.CopyTo(properties);
                    model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body);
                }).ConfigureAwait(false);
            }

            eventBus.Publish(new PublishedMessageEvent(exchange.Name, routingKey, rawMessage.Properties, rawMessage.Body));

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat(
                    "Published to exchange {exchange} with routingKey={routingKey} and correlationId={correlationId}",
                    exchange.Name,
                    routingKey,
                    messageProperties.CorrelationId
                    );
            }
        }
예제 #24
0
        public virtual async Task PublishAsync(
            IExchange exchange,
            string routingKey,
            bool mandatory,
            MessageProperties messageProperties,
            byte[] body)
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(messageProperties, "messageProperties");
            Preconditions.CheckNotNull(body, "body");

            // Fix me: It's very hard now to move publish logic to separate abstraction, just leave it here.
            var rawMessage = produceConsumeInterceptor.OnProduce(new RawMessage(messageProperties, body));

            if (connectionConfiguration.PublisherConfirms)
            {
                var timeBudget = new TimeBudget(TimeSpan.FromSeconds(connectionConfiguration.Timeout)).Start();
                while (!timeBudget.IsExpired())
                {
                    var confirmsWaiter = await clientCommandDispatcher.InvokeAsync(model =>
                    {
                        var properties = model.CreateBasicProperties();
                        rawMessage.Properties.CopyTo(properties);
                        var waiter = confirmationListener.GetWaiter(model);

                        try
                        {
                            model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body);
                        }
                        catch (Exception)
                        {
                            waiter.Cancel();
                            throw;
                        }

                        return(waiter);
                    }).ConfigureAwait(false);

                    try
                    {
                        await confirmsWaiter.WaitAsync(timeBudget.GetRemainingTime()).ConfigureAwait(false);

                        break;
                    }
                    catch (PublishInterruptedException)
                    {
                    }
                }
            }
            else
            {
                await clientCommandDispatcher.InvokeAsync(model =>
                {
                    var properties = model.CreateBasicProperties();
                    rawMessage.Properties.CopyTo(properties);
                    model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body);
                }).ConfigureAwait(false);
            }
            eventBus.Publish(new PublishedMessageEvent(exchange.Name, routingKey, rawMessage.Properties, rawMessage.Body));
            logger.DebugWrite("Published to exchange: '{0}', routing key: '{1}', correlationId: '{2}'", exchange.Name, routingKey, messageProperties.CorrelationId);
        }
예제 #25
0
        /// <inheritdoc />
        public virtual async Task PublishAsync(
            IExchange exchange,
            string routingKey,
            bool mandatory,
            MessageProperties messageProperties,
            byte[] body,
            CancellationToken cancellationToken
            )
        {
            Preconditions.CheckNotNull(exchange, "exchange");
            Preconditions.CheckShortString(routingKey, "routingKey");
            Preconditions.CheckNotNull(messageProperties, "messageProperties");
            Preconditions.CheckNotNull(body, "body");

            using var cts = cancellationToken.WithTimeout(configuration.Timeout);

            var rawMessage = produceConsumeInterceptor.OnProduce(new ProducedMessage(messageProperties, body));

            if (configuration.PublisherConfirms)
            {
                while (true)
                {
                    var pendingConfirmation = await clientCommandDispatcher.InvokeAsync(model =>
                    {
                        var confirmation = confirmationListener.CreatePendingConfirmation(model);
                        rawMessage.Properties.SetConfirmationId(confirmation.Id);
                        var properties = model.CreateBasicProperties();
                        rawMessage.Properties.CopyTo(properties);
                        try
                        {
                            model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body);
                        }
                        catch (Exception)
                        {
                            confirmation.Cancel();
                            throw;
                        }
                        return(confirmation);
                    }, ChannelDispatchOptions.PublishWithConfirms, cts.Token).ConfigureAwait(false);

                    try
                    {
                        await pendingConfirmation.WaitAsync(cts.Token).ConfigureAwait(false);

                        break;
                    }
                    catch (PublishInterruptedException)
                    {
                    }
                }
            }
            else
            {
                await clientCommandDispatcher.InvokeAsync(model =>
                {
                    var properties = model.CreateBasicProperties();
                    rawMessage.Properties.CopyTo(properties);
                    model.BasicPublish(exchange.Name, routingKey, mandatory, properties, rawMessage.Body);
                }, ChannelDispatchOptions.Publish, cts.Token).ConfigureAwait(false);
            }

            eventBus.Publish(new PublishedMessageEvent(exchange.Name, routingKey, rawMessage.Properties, rawMessage.Body));

            if (logger.IsDebugEnabled())
            {
                logger.DebugFormat(
                    "Published to exchange {exchange} with routingKey={routingKey} and correlationId={correlationId}",
                    exchange.Name,
                    routingKey,
                    messageProperties.CorrelationId
                    );
            }
        }