private ushort GetProperPrefetchSize(IPrioritySubscriptionOption subscriptionOption, uint priority)
        {
            var prefetchSize = subscriptionOption.QueuePrefetchSizeSelector != null
                             ? subscriptionOption.QueuePrefetchSizeSelector(priority)
                             : subscriptionOption.QueuePrefetchSize;

            if (prefetchSize <= 0)
            {
                prefetchSize = Global.PreFetchSize;
            }

            if (prefetchSize > ushort.MaxValue)
            {
                _watcher.WarnFormat("The prefetch size is too high {0}, the queue will prefetch the maximum {1} msgs", prefetchSize, ushort.MaxValue);
            }

            return((ushort)Math.Min(ushort.MaxValue, prefetchSize));
        }
 private string GetPriorityQueueName <T>(IPrioritySubscriptionOption subscriptionOption, uint priority)
 {
     return((subscriptionOption.RouteFinder ?? _routeFinder).FindQueueName <T>(subscriptionOption.SubscriptionName) +
            (subscriptionOption.QueueSuffixNameConvention ?? PriorityQueuesRabbitSetup.GlobalPriorityQueueSuffix).Get(typeof(T), priority));
 }
        private CompositeSubscription CreateSubscription <T>(IPrioritySubscriptionOption subscriptionOption, Func <IModel, string, IBasicConsumer> createConsumer)
        {
            var comparer = TryGetComparer(subscriptionOption.ComparerType);
            var compositeSubscription = new CompositeSubscription();

            uint maxSize = 0;

            for (uint level = 0; level <= subscriptionOption.MaxPriorityLevel; level++)
            {
                maxSize += GetProperPrefetchSize(subscriptionOption, level);
            }
            var priorityQueue = new InMemoryPriorityQueue <GenericPriorityMessage <BasicDeliverEventArgs> >(maxSize, comparer);

            var sharedSemaphore = string.Format("{0}{1}", subscriptionOption.SubscriptionName, Guid.NewGuid());

            for (uint level = 0; level <= subscriptionOption.MaxPriorityLevel; level++)
            {
                var subscription = new Subscription {
                    SubscriptionName = subscriptionOption.SubscriptionName
                };
                uint priority = level;
                var  id       = Guid.NewGuid();

                Action subscriptionAction = () =>
                {
                    subscription.QueueName = GetPriorityQueueName <T>(subscriptionOption, priority);
                    if (string.IsNullOrEmpty(subscription.ConsumerTag))
                    {
                        // Keep the key here because it's used for the key indexes of internal cache
                        subscription.ConsumerTag = string.Format("{0}-{1}", subscriptionOption.SubscriptionName, Guid.NewGuid());
                    }
                    var channel = _connection.CreateChannel();
                    channel.ModelShutdown += (c, reason) =>
                    {
                        RaiseConsumerDisconnectedEvent(subscription);
                        TryReconnect(c, id, reason);
                    };

                    var prefetchSize = GetProperPrefetchSize(subscriptionOption, priority);
                    channel.BasicQos(0, prefetchSize, false);

                    _createdChannels.Add(channel);

                    var consumer         = createConsumer(channel, subscription.ConsumerTag);
                    var priorityConsumer = consumer as PriorityBurrowConsumer;
                    if (priorityConsumer == null)
                    {
                        throw new NotSupportedException(string.Format("Expected PriorityBurrowConsumer but was {0}", consumer == null ? "NULL" : consumer.GetType().Name));
                    }

                    priorityConsumer.Init(priorityQueue, compositeSubscription, priority, sharedSemaphore);
                    priorityConsumer.ConsumerTag = subscription.ConsumerTag;
                    subscription.SetChannel(channel);

                    //NOTE: The message will still be on the Unacknowledged list until it's processed and the method
                    //      DoAck is call.
                    channel.BasicConsume(subscription.QueueName,
                                         false /* noAck, must be false */,
                                         subscription.ConsumerTag, priorityConsumer);
                    _watcher.InfoFormat("Subscribed to: {0} with subscriptionName: {1}",
                                        subscription.QueueName,
                                        subscription.SubscriptionName);
                    priorityConsumer.Ready();
                };

                _subscribeActions[id] = subscriptionAction;
                TrySubscribe(subscriptionAction);
                compositeSubscription.AddSubscription(subscription);
            }
            return(compositeSubscription);
        }