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.LogInformation("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 deadLetterQueueName = GetDeadLetterQueueName(deliveryArgs.Exchange, retryAck.Span); var deadLetterExchange = context?.GetConsumerConfiguration()?.Exchange.Name ?? deliveryArgs.Exchange; await TopologyProvider.DeclareQueueAsync(new QueueDeclaration { Name = deadLetterQueueName, Durable = true, Arguments = new Dictionary <string, object> { { QueueArgument.DeadLetterExchange, deadLetterExchange }, { QueueArgument.Expires, Convert.ToInt32(retryAck.Span.Add(TimeSpan.FromSeconds(1)).TotalMilliseconds) }, { QueueArgument.MessageTtl, Convert.ToInt32(retryAck.Span.TotalMilliseconds) } } }); await TopologyProvider.BindQueueAsync(deadLetterQueueName, deadLeterExchangeName, deliveryArgs.RoutingKey, deliveryArgs.BasicProperties.Headers); using (var publishChannel = await ChannelFactory.CreateChannelAsync(token)) { publishChannel.BasicPublish(deadLeterExchangeName, deliveryArgs.RoutingKey, false, deliveryArgs.BasicProperties, deliveryArgs.Body); } await TopologyProvider.UnbindQueueAsync(deadLetterQueueName, deadLeterExchangeName, deliveryArgs.RoutingKey, deliveryArgs.BasicProperties.Headers); context.Properties.AddOrReplace(PipeKey.MessageAcknowledgement, new Ack()); await Next.InvokeAsync(context, token); }