protected virtual Task AckMessageIfApplicable(IPipeContext context)
        {
            var autoAck = context.GetConsumeConfiguration()?.AutoAck;

            if (!autoAck.HasValue)
            {
                _logger.Debug("Unable to ack original message. Can not determine if AutoAck is configured.");
                return(Task.FromResult(0));
            }
            if (autoAck.Value)
            {
                _logger.Debug("Consuming in AutoAck mode. No ack'ing will be performed");
                return(Task.FromResult(0));
            }
            var deliveryTag = context.GetDeliveryEventArgs()?.DeliveryTag;

            if (deliveryTag == null)
            {
                _logger.Info("Unable to ack original message. Delivery tag not found.");
                return(Task.FromResult(0));
            }
            var consumerChannel = context.GetConsumer()?.Model;

            if (consumerChannel != null && consumerChannel.IsOpen && deliveryTag.HasValue)
            {
                _logger.Debug("Acking message with {deliveryTag} on channel {channelNumber}", deliveryTag, consumerChannel.ChannelNumber);
                consumerChannel.BasicAck(deliveryTag.Value, false);
            }
            return(Task.FromResult(0));
        }
Пример #2
0
 protected virtual Task BindQueueAsync(string queue, string exchange, string routingKey, IPipeContext context, CancellationToken ct)
 {
     return(TopologyProvider.BindQueueAsync(queue, exchange, routingKey, context.GetConsumeConfiguration()?.Arguments));
 }
        public override async Task InvokeAsync(IPipeContext context, CancellationToken token = default(CancellationToken))
        {
            var ack = GetMessageAcknowledgement(context);

            if (!(ack is Retry retryAck))
            {
                await Next.InvokeAsync(context, token);

                return;
            }

            var deadLeterExchangeName = GetDeadLetterExchangeName(retryAck.Span);
            await TopologyProvider.DeclareExchangeAsync(new ExchangeDeclaration
            {
                Name         = deadLeterExchangeName,
                Durable      = true,
                ExchangeType = ExchangeType.Direct
            });

            var deliveryArgs = GetDeliveryEventArgs(context);

            //_logger.Info("Message is marked for Retry. Will be published on exchange {exchangeName} with routing key {routingKey} in {retryIn}", deliveryArgs.Exchange, deliveryArgs.RoutingKey, retryAck.Span);
            UpdateRetryHeaders(deliveryArgs, context);

            var consumeConfiguration = context.GetConsumeConfiguration();
            var deadLetterQueueName  = GetDeadLetterQueueName(consumeConfiguration.QueueName, retryAck.Span);

            var retryExchangeName = "default_retry_exchange";
            var retryRoutingKey   = $"{consumeConfiguration.QueueName}_{consumeConfiguration.RoutingKey}";

            await TopologyProvider.DeclareExchangeAsync(new ExchangeDeclaration
            {
                Name         = retryExchangeName,
                Durable      = true,
                AutoDelete   = true,
                ExchangeType = ExchangeType.Topic
            });

            await TopologyProvider.BindQueueAsync(consumeConfiguration.QueueName, retryExchangeName, retryRoutingKey);

            await TopologyProvider.DeclareQueueAsync(new QueueDeclaration
            {
                Name      = deadLetterQueueName,
                Durable   = true,
                Arguments = new Dictionary <string, object>
                {
                    { QueueArgument.DeadLetterExchange, retryExchangeName },
                    { "x-dead-letter-routing-key", retryRoutingKey },
                    { QueueArgument.Expires, Convert.ToInt32(retryAck.Span.Add(TimeSpan.FromSeconds(1)).TotalMilliseconds) },
                    { QueueArgument.MessageTtl, Convert.ToInt32(retryAck.Span.TotalMilliseconds) }
                }
            });

            await TopologyProvider.BindQueueAsync(deadLetterQueueName, deadLeterExchangeName, retryRoutingKey);

            using (var publishChannel = await ChannelFactory.CreateChannelAsync(token))
            {
                publishChannel.BasicPublish(deadLeterExchangeName, retryRoutingKey, false, deliveryArgs.BasicProperties, deliveryArgs.Body);
            }
            await TopologyProvider.UnbindQueueAsync(deadLetterQueueName, deadLeterExchangeName, retryRoutingKey);

            context.Properties.AddOrReplace(PipeKey.MessageAcknowledgement, new Ack());
            await Next.InvokeAsync(context, token);
        }