private CompositeSubscription CreateSubscription <T>(string subscriptionName, uint maxPriorityLevel, Func <IModel, string, IBasicConsumer> createConsumer, Type comparerType) { var comparer = TryGetComparer(comparerType); var compositeSubscription = new CompositeSubscription(); var maxSize = Global.PreFetchSize * ((int)maxPriorityLevel + 1); var priorityQueue = new InMemoryPriorityQueue <GenericPriorityMessage <BasicDeliverEventArgs> >(maxSize, comparer); var sharedSemaphore = string.Format("{0}{1}", subscriptionName, Guid.NewGuid()); for (uint level = 0; level <= maxPriorityLevel; level++) { var subscription = new Subscription { SubscriptionName = subscriptionName }; uint priority = level; var id = Guid.NewGuid(); Action subscriptionAction = () => { subscription.QueueName = _routeFinder.FindQueueName <T>(subscriptionName) + PriorityQueuesRabbitSetup.GlobalPriorityQueueSuffix.Get(typeof(T), 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}", subscriptionName, Guid.NewGuid()); } var channel = _connection.CreateChannel(); channel.ModelShutdown += (c, reason) => { RaiseConsumerDisconnectedEvent(subscription); TryReconnect(c, id, reason); }; if (Global.PreFetchSize <= ushort.MaxValue) { channel.BasicQos(0, (ushort)Global.PreFetchSize, false); } else { _watcher.WarnFormat("The prefetch size is too high {0}, the queue will prefetch all the msgs", Global.PreFetchSize); } _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); }
private CompositeSubscription CreateSubscription <T>(IPrioritySubscriptionOption subscriptionOption, Func <IModel, 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 += (o, reason) => { RaiseConsumerDisconnectedEvent(subscription); TryReconnect((IModel)o, id, reason); }; var prefetchSize = GetProperPrefetchSize(subscriptionOption, priority); channel.BasicQos(0, prefetchSize, false); _createdChannels.Add(channel); var consumer = createConsumer(channel); 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.OutstandingDeliveryTags[subscription.ConsumerTag] = new List <ulong>(); 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); }