private void ConsumeByPull() { foreach (var topic in _topics.Keys) { var queueCount = _topics[topic]; var subscribeQueues = GetSubscribeQueues(queueCount, _consumerCount, _consumerSequence); var subTopic = GetSubTopic(topic); var channels = new ConcurrentDictionary <byte, Tuple <IModel, Thread> >(); if (!_globalChannels.TryAdd(subTopic, channels)) { throw new Exception($"{subTopic} has subscribed."); } for (byte queueIndex = 0; queueIndex < queueCount; queueIndex++) { if (subscribeQueues == null || !subscribeQueues.Any(a => a == queueIndex)) { continue; } channels.TryGetValue(queueIndex, out Tuple <IModel, Thread> channelTuple); if (channelTuple != null) { continue; } try { var queueName = GetQueue(topic, queueIndex); var channel = _amqpConnection.CreateModel(); var consumerThread = new Thread((state) => { var currentChannelTopicQueueIndexPair = (Tuple <IModel, string, int>)state; var currentChannel = currentChannelTopicQueueIndexPair.Item1; var currentTopic = currentChannelTopicQueueIndexPair.Item2; var currentQueueIndex = currentChannelTopicQueueIndexPair.Item3; var currentQueueName = GetQueue(currentTopic, currentQueueIndex); int unackCount = 0; int noMsgCount = 0; while (true) { if (!currentChannel.IsOpen) { var closeReason = currentChannel.CloseReason; if (closeReason.ReplyCode == RabbitMQConstants.ConnectionForced) { break; } if (closeReason.ReplyCode == RabbitMQConstants.ChannelError) { Thread.Sleep(1000); continue; } else { throw new Exception($"{closeReason.ReplyText}"); } } if (OnMessageReceived == null) { Thread.Sleep(1000); continue; } if (unackCount > _prefetchCount) { // 当消费堆积数,达到设定值后,将延迟1秒拉消息 Thread.Sleep(1000); } try { var mqMessage = currentChannel.BasicGet(currentQueueName, false); if (mqMessage == null) { if (noMsgCount < 1000) { // 约10秒以内 Interlocked.Increment(ref noMsgCount); Thread.Sleep(10); } else if (noMsgCount < 1500) { // 约1分钟以内 Interlocked.Increment(ref noMsgCount); Thread.Sleep(100); } else { // 超过1分钟 Thread.Sleep(1000); } continue; } Interlocked.Exchange(ref noMsgCount, 0); Interlocked.Increment(ref unackCount); var context = new MessageHandlingTransportationContext(topic, currentQueueIndex, _groupName, currentChannel, mqMessage.DeliveryTag, new Dictionary <string, object> { { MessagePropertyConstants.MESSAGE_ID, mqMessage.BasicProperties.MessageId }, { MessagePropertyConstants.MESSAGE_TYPE, mqMessage.BasicProperties.Type }, { MessagePropertyConstants.TIMESTAMP, mqMessage.BasicProperties.Timestamp.UnixTime == 0 ? DateTime.Now : DateTime2UnixTime.FromUnixTime(mqMessage.BasicProperties.Timestamp.UnixTime) }, { MessagePropertyConstants.CONTENT_TYPE, string.IsNullOrEmpty(mqMessage.BasicProperties.ContentType) ? "text/json" : mqMessage.BasicProperties.ContentType }, { MessagePropertyConstants.BODY, mqMessage.Body }, { MessagePropertyConstants.ROUTING_KEY, mqMessage.RoutingKey } }); context.OnAck += (sender, e) => Interlocked.Decrement(ref unackCount); OnMessageReceived.Invoke(this, new MessageReceivedEventArgs(context)); } catch { } } }) { IsBackground = false }; channelTuple = new Tuple <IModel, Thread>(channel, consumerThread); consumerThread.Start(new Tuple <IModel, string, int>(channel, topic, queueIndex)); } finally { channels.TryAdd(queueIndex, channelTuple); } } } }
private void ConsumeByPush() { foreach (var topic in _topics.Keys) { var queueCount = _topics[topic]; var subscribeQueues = GetSubscribeQueues(queueCount, _consumerCount, _consumerSequence); var subTopic = GetSubTopic(topic); var consumers = new ConcurrentDictionary <byte, EventingBasicConsumer>(); if (!_globalConsumers.TryAdd(subTopic, consumers)) { throw new Exception($"{subTopic} has subscribed."); } for (byte queueIndex = 0; queueIndex < queueCount; queueIndex++) { if (subscribeQueues == null || !subscribeQueues.Any(a => a == queueIndex)) { continue; } consumers.TryGetValue(queueIndex, out EventingBasicConsumer consumer); if (consumer != null) { continue; } var channel = _amqpConnection.CreateModel(); channel.BasicQos(0, _prefetchCount, false); consumer = new EventingBasicConsumer(channel); try { consumer.Received += (sender, e) => { var currentConsumer = ((EventingBasicConsumer)sender); var currentChannel = currentConsumer.Model; while (!consumers.Any(w => w.Value.Model == currentChannel)) { Thread.Sleep(1000); } if (OnMessageReceived != null) { var currentTopic = e.Exchange.IndexOf("-delayed") > 0 ? e.Exchange.Substring(0, e.Exchange.LastIndexOf("-delayed")) : e.Exchange; var currentQueueIndex = consumers.First(w => w.Value.Model == currentChannel).Key; var context = new MessageHandlingTransportationContext(currentTopic, currentQueueIndex, _groupName, channel, e.DeliveryTag, new Dictionary <string, object> { { MessagePropertyConstants.MESSAGE_ID, e.BasicProperties.MessageId }, { MessagePropertyConstants.MESSAGE_TYPE, e.BasicProperties.Type }, { MessagePropertyConstants.TIMESTAMP, e.BasicProperties.Timestamp.UnixTime == 0 ? DateTime.Now : DateTime2UnixTime.FromUnixTime(e.BasicProperties.Timestamp.UnixTime) }, { MessagePropertyConstants.CONTENT_TYPE, string.IsNullOrEmpty(e.BasicProperties.ContentType) ? "text/json" : e.BasicProperties.ContentType }, { MessagePropertyConstants.BODY, e.Body }, { MessagePropertyConstants.ROUTING_KEY, e.RoutingKey } }); try { OnMessageReceived.Invoke(this, new MessageReceivedEventArgs(context)); } catch { } } }; consumer.Shutdown += (sender, e) => { var currentConsumer = ((EventingBasicConsumer)sender); var currentChannel = currentConsumer.Model; if (e.ReplyCode == RabbitMQConstants.ConnectionForced) { return; } while (e.ReplyCode == RabbitMQConstants.ChannelError && !currentChannel.IsOpen) { Thread.Sleep(1000); } }; channel.BasicConsume(GetQueue(topic, queueIndex), false, $"{_amqpConnection.ClientProvidedName}_consumer{queueIndex}", new Dictionary <string, object>(), consumer); } finally { consumers.TryAdd(queueIndex, consumer); } } } }