// Application starting point
        public void Run(bool useSenderServiceKeepConnection)
        {
            _useSenderServiceKeepConnection = useSenderServiceKeepConnection;

            _senderServiceKeepConnection.ServiceDescription = $"service to send message - keep connection created at {DateTime.Now}";
            _senderService.ServiceDescription = "service to send messages";

            var retryQueueDetails = new RetryQueueDetails
            {
                RetentionPeriodInRetryQueueMilliseconds    = _config.BrokerRetentionPeriodInRetryQueueSeconds * 1000,
                RetentionPeriodInRetryQueueMillisecondsMax = _config.BrokerRetentionPeriodInRetryQueueSecondsMax * 1000,
                RetryQueue = _config.BrokerRetryQueue
            };



            _consumerService.StartConsumers("consumers_Tag_A", retryQueueDetails, totalConsumers: 2);
            _consumerService.StartConsumers("consumers_Tag_B", retryQueueDetails, totalConsumers: 2);

            _logger.LogInformation($"Starting consumers...");

            var details = _consumerService.GetConsumerDetails();

            if (details != null)
            {
                foreach (var consumerInfo in details)
                {
                    _logger.LogInformation($"consumer '{consumerInfo.Name}' connected to {consumerInfo.ConnectedToHost}:{consumerInfo.ConnectedToPort} started at {consumerInfo.ConnectionTime:yyyy-MM-dd HH:mm:ss}");
                }
            }
        }
        /// <summary>
        /// StartConsumers - start consumers and connect them to a queue.
        /// </summary>
        /// <param name="consumerName">Consumer name</param>
        /// <param name="retryQueueDetails">Retry queue details if a message needs to be requeued with a delay (a Dead letter exchange must be defined)</param>
        /// <param name="queueName">Queue where the consumers will connect (optional - if not defined, the config value is used)</param>
        /// <param name="totalConsumers">Total consumers to start (optional - if not defined, the config value is used)</param>
        /// <param name="createQueue">Create queue to connect when starting consumers (optional - default is false)</param>
        /// <exception cref="RabbitMQClientException"></exception>
        public void StartConsumers(string consumerName, RetryQueueDetails retryQueueDetails, string queueName = null, byte?totalConsumers = null, bool createQueue = false)
        {
            var config = (IBrokerConfigConsumers)_config;

            var totalConsumersToStart = totalConsumers ?? config.TotalInstances;

            if (totalConsumersToStart <= 0)
            {
                throw new ArgumentException("Invalid total number of consumers to start");
            }

            var triedCreateQueue = false;

            for (var i = 0; i < totalConsumersToStart; i++)
            {
                var routingKeyOrQueueName =
                    string.IsNullOrWhiteSpace(queueName) ? config.RoutingKeyOrQueueName : queueName;

                var totalCreatedConsumers = _consumers.Count;

                var connection = GetConnection(ServiceDescription + "_" + i, totalCreatedConsumers, MaxChannelsPerConnection);

                var channel = connection.CreateModel();

                if (createQueue && !triedCreateQueue)
                {
                    try
                    {
                        RabbitMqUtilities.CreateQueueOrGetInfo(routingKeyOrQueueName, channel);
                        triedCreateQueue = true;
                    }
                    catch (Exception e)
                    {
                        throw new RabbitMqClientException($"Unable do create queue. Details: {e.Message}", e);
                    }
                }

                var consumer = new AsyncEventingBasicConsumerExtended(channel)
                {
                    ConnectedToPort = connection.Endpoint.Port,
                    ConnectedToHost = connection.Endpoint.HostName,
                    ConnectionTime  = DateTime.Now,
                    Id = i,
                    RetentionPeriodInRetryQueueMilliseconds    = retryQueueDetails?.RetentionPeriodInRetryQueueMilliseconds ?? 0,
                    RetentionPeriodInRetryQueueMillisecondsMax = retryQueueDetails?.RetentionPeriodInRetryQueueMillisecondsMax ?? 0,
                    RetryQueue = retryQueueDetails?.RetryQueue
                };

                consumer.Received += Consumer_Received;
                consumer.Shutdown += Consumer_Shutdown;

                var tag = $"{consumerName}_{i}";

                consumer.ConsumerTag = tag;

                _consumers.Add(consumer);

                channel.BasicConsume(routingKeyOrQueueName, false, tag, consumer);
            }
        }