void MigrateQueue(IModel channel, int delayLevel, CancellationToken cancellationToken) { var currentDelayQueue = $"nsb.delay-level-{delayLevel:00}"; var messageCount = channel.MessageCount(currentDelayQueue); var declaredDestinationQueues = new HashSet <string>(); if (messageCount > 0) { if (!quietMode) { console.Write($"Processing {messageCount} messages at delay level {delayLevel:00}. "); } int skippedMessages = 0; int processedMessages = 0; for (int i = 0; i < messageCount && !cancellationToken.IsCancellationRequested; i++) { var message = channel.BasicGet(currentDelayQueue, false); if (message == null) { // Queue is empty break; } if (MessageIsInvalid(message)) { skippedMessages++; if (!poisonQueueCreated) { channel.QueueDeclare(poisonMessageQueue, true, false, false); poisonQueueCreated = true; } channel.BasicPublish(string.Empty, poisonMessageQueue, message.BasicProperties, message.Body); channel.WaitForConfirmsOrDie(); channel.BasicAck(message.DeliveryTag, false); continue; } var messageHeaders = message.BasicProperties.Headers; var delayInSeconds = (int)messageHeaders[DelayInfrastructure.DelayHeader]; var timeSent = GetTimeSent(message); var(destinationQueue, newRoutingKey, newDelayLevel) = GetNewRoutingKey(delayInSeconds, timeSent, message.RoutingKey, DateTimeOffset.UtcNow); // Make sure the destination queue is bound to the delivery exchange to ensure delivery if (!declaredDestinationQueues.Contains(destinationQueue)) { routingTopology.BindToDelayInfrastructure(channel, destinationQueue, DelayInfrastructure.DeliveryExchange, DelayInfrastructure.BindingKey(destinationQueue)); declaredDestinationQueues.Add(destinationQueue); } var publishExchange = DelayInfrastructure.LevelName(newDelayLevel); if (messageHeaders != null) { //These headers need to be removed so that they won't be copied to an outgoing message if this message gets forwarded messageHeaders.Remove(DelayInfrastructure.XDeathHeader); messageHeaders.Remove(DelayInfrastructure.XFirstDeathExchangeHeader); messageHeaders.Remove(DelayInfrastructure.XFirstDeathQueueHeader); messageHeaders.Remove(DelayInfrastructure.XFirstDeathReasonHeader); } channel.BasicPublish(publishExchange, newRoutingKey, message.BasicProperties, message.Body); channel.WaitForConfirmsOrDie(); channel.BasicAck(message.DeliveryTag, false); processedMessages++; } if (!quietMode) { console.WriteLine($"{processedMessages} successful, {skippedMessages} skipped."); } } else { if (!quietMode) { console.WriteLine($"No messages to process at delay level {delayLevel:00}."); } } }
public Task Run(string endpointName, string?errorQueue, string?auditQueue, IEnumerable <string> instanceDiscriminators, CancellationToken cancellationToken = default) { console.WriteLine("Connecting to broker"); using var connection = connectionFactory.CreateAdministrationConnection(); using var channel = connection.CreateModel(); console.WriteLine("Checking for delay infrastructure v2"); try { channel.ExchangeDeclarePassive(DelayInfrastructure.DeliveryExchange); } catch (OperationInterruptedException) { console.Error.Write("Fail: Delay infrastructure v2 not found.\n"); throw; } console.WriteLine($"Creating queues"); var receivingAddresses = new List <string>() { endpointName }; if (instanceDiscriminators.Any()) { receivingAddresses.AddRange(instanceDiscriminators.Select(discriminator => $"{endpointName}-{discriminator}")); } var sendingAddresses = new List <string>(); if (!string.IsNullOrWhiteSpace(errorQueue)) { sendingAddresses.Add(errorQueue); } if (!string.IsNullOrWhiteSpace(auditQueue)) { sendingAddresses.Add(auditQueue); } routingTopology.Initialize(channel, receivingAddresses, sendingAddresses); foreach (var receivingAddress in receivingAddresses) { routingTopology.BindToDelayInfrastructure(channel, receivingAddress, DelayInfrastructure.DeliveryExchange, DelayInfrastructure.BindingKey(receivingAddress)); } console.WriteLine($"Completed successfully"); return(Task.CompletedTask); }