Пример #1
0
 /// <summary>
 /// 获取新序号
 /// </summary>
 /// <param name="dateTime"></param>
 /// <returns></returns>
 public void Generate(DateTime dateTime)
 {
     lock (_locker)
     {
         Interlocked.Increment(ref _versionId);
         var unixTime = DateTime2UnixTime.ToUnixTime(dateTime.Date.AddHours(dateTime.Hour));
         if (unixTime <= _unixTime)
         {
             ++Sequence;
         }
         else
         {
             _unixTime = unixTime;
             Infix     = DateTime2UnixTime.FromUnixTime(_unixTime).ToString("yyMMddHH");
             Sequence  = 1;
         }
     }
 }
Пример #2
0
 /// <summary>
 /// 从字节数组中加载
 /// </summary>
 /// <param name="bytes">48字节</param>
 /// <exception cref="InvalidCastException"></exception>
 public BusinessCode(byte[] bytes)
 {
     if (bytes != null && bytes.Length == BYTES_LENGTH)
     {
         ApplicationId = new Guid(bytes.Take(16).ToArray());
         CodeType      = BitConverter.ToInt32(bytes, 16);
         _unixTime     = BitConverter.ToInt64(bytes, 20);
         Infix         = DateTime2UnixTime.FromUnixTime(_unixTime).ToString("yyMMddHH");
         Sequence      = BitConverter.ToInt32(bytes, 28);
         if (Sequence < 1)
         {
             throw new InvalidCastException("Sequence is invalid");
         }
         _versionId = BitConverter.ToInt64(bytes, 40);
         if (_versionId < 1)
         {
             throw new InvalidCastException("Version is invalid");
         }
     }
     else
     {
         throw new InvalidCastException("Data must 48 bytes");
     }
 }
Пример #3
0
        /// <summary>
        /// 处理消息队列的消息
        /// </summary>
        /// <param name="currentConsumer"></param>
        /// <param name="props"></param>
        /// <param name="exchangeName"></param>
        /// <param name="queueName"></param>
        /// <param name="routingKey"></param>
        /// <param name="body"></param>
        /// <param name="deliveryTag"></param>
        /// <param name="redelivered"></param>
        /// <param name="dropIfMessageHandlerNotRegistered">消息处理器未注册时直接丢弃</param>
        protected void HandleMessage(IBasicConsumer currentConsumer, IBasicProperties props, string exchangeName, string queueName, string routingKey, byte[] body, ulong deliveryTag, bool redelivered, bool dropIfMessageHandlerNotRegistered)
        {
            var currentChannel  = currentConsumer.Model;
            var messageTypeName = props.Type;

            if (string.IsNullOrEmpty(props.Type))
            {
                // 如果未传入类型,则以队列名作为类型名
                if (queueName.StartsWith("rpc."))
                {
                    messageTypeName = queueName.Substring(4);
                }
                else
                {
                    messageTypeName = queueName;
                }
            }
            var context = new MessageHandlingTransportationContext(exchangeName, queueName, new Dictionary <string, object> {
                { MessagePropertyConstants.MESSAGE_ID, string.IsNullOrEmpty(props.MessageId) ? Guid.NewGuid().ToString() : props.MessageId },
                { MessagePropertyConstants.MESSAGE_TYPE, messageTypeName },
                { MessagePropertyConstants.TIMESTAMP, props.Timestamp.UnixTime == 0 ? DateTime.Now : DateTime2UnixTime.FromUnixTime(props.Timestamp.UnixTime) },
                { MessagePropertyConstants.CONTENT_TYPE, string.IsNullOrEmpty(props.ContentType) ? Serializer.ContentType : props.ContentType },
                { MessagePropertyConstants.PAYLOAD, Serializer.GetString(body) },
                { MessagePropertyConstants.ROUTING_KEY, routingKey },
                { MessagePropertyConstants.REPLY_TO, props.ReplyTo },
                { MessagePropertyConstants.CORRELATION_ID, props.CorrelationId }
            });
            var messageHandlerCategory = string.Empty;

            try
            {
                if (_messageTypes.ContainsKey(messageTypeName))
                {
                    object message = null;
                    try
                    {
                        message = Serializer.Deserialize(body, _messageTypes[messageTypeName]);
                    }
                    catch
                    {
                        // 消费端无法反序列化消息,则直接丢弃
                        _logger.Error($"Message [\"{context.GetMessageType()}\"] \"{context.GetPayload()}\" deserialized fail in queue \"{queueName}\".");
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }

                    if (message == null)
                    {
                        return;
                    }
                    var messageHandler = GetMessageHandler(messageTypeName);
                    if (messageHandler != null)
                    {
                        messageHandlerCategory = MessageHandlerTypeAttribute.GetCategory(messageHandler.GetType());
                        TriggerOnMessageReceived(new MessageReceivedEventArgs(messageHandlerCategory, this.GetReceiverType(), context));
                        RetryPolicy.Retry(() =>
                        {
                            try
                            {
                                messageHandler.GetType().InvokeMember("Handle",
                                                                      BindingFlags.InvokeMethod
                                                                      | BindingFlags.Public
                                                                      | BindingFlags.Instance,
                                                                      null, messageHandler, new object[] { message, context });
                            }
                            catch (Exception handleEx)
                            {
                                context.LastException = handleEx is TargetInvocationException ? handleEx.InnerException : handleEx;
                                throw handleEx;
                            }
                        }, cancelOnFailed: (retryCount, retryException) =>
                        {
                            if (retryCount >= MaxRetryCount)
                            {
                                return(true);
                            }
                            context.LastException = retryException is TargetInvocationException ? retryException.InnerException : retryException;
                            context.RetryCount    = retryCount + 1;
                            return(false);
                        });

                        TriggerOnMessageHandlingSucceeded(new MessageHandlingSucceededEventArgs(messageHandlerCategory, this.GetReceiverType(), context));
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                    else if (dropIfMessageHandlerNotRegistered)
                    {
                        // 消费端无对应的消息处理器,则忽略,直接响应成功
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                    else
                    {
                        context.LastException = new MessageHandlerNotRegisteredException(messageTypeName);
                        if (TriggerOnMessageHandlingFailed(new MessageHandlingFailedEventArgs(messageHandlerCategory, this.GetReceiverType(), context)))
                        {
                            LockerExecuter.Execute(currentChannel, () =>
                            {
                                RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                                  retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                                  retryTimeInterval: 1000);
                            });
                        }
                        else
                        {
                            LockerExecuter.Execute(currentChannel, () =>
                            {
                                RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                                  retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                                  retryTimeInterval: 1000);
                            });
                        }
                    }
                }
                else if (dropIfMessageHandlerNotRegistered)
                {
                    // 消费端无对应的消息处理器,则忽略,直接响应成功
                    LockerExecuter.Execute(currentChannel, () =>
                    {
                        RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                          retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                          retryTimeInterval: 1000);
                    });
                }
                else
                {
                    context.LastException = new MessageHandlerNotRegisteredException(messageTypeName);
                    if (TriggerOnMessageHandlingFailed(new MessageHandlingFailedEventArgs(messageHandlerCategory, this.GetReceiverType(), context)))
                    {
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                    else
                    {
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                // 消费端处理其他异常
                context.LastException = ex is TargetInvocationException ? ex.InnerException : ex;
                if (TriggerOnMessageHandlingFailed(new MessageHandlingFailedEventArgs(messageHandlerCategory, this.GetReceiverType(), context)))
                {
                    LockerExecuter.Execute(currentChannel, () =>
                    {
                        RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                          retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                          retryTimeInterval: 1000);
                    });
                }
                else
                {
                    LockerExecuter.Execute(currentChannel, () =>
                    {
                        RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                          retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                          retryTimeInterval: 1000);
                    });
                }
            }
        }
Пример #4
0
        /// <summary>
        /// 重发到交换器
        /// </summary>
        /// <param name="exchangeName">交换器名</param>
        /// <param name="messageId">消息ID</param>
        /// <param name="messageTypeName">消息类型名</param>
        /// <param name="messageTimestamp">消息时间戳</param>
        /// <param name="messageBody">消息体</param>
        /// <param name="routingKey">路由键</param>
        /// <param name="correlationId">关联ID</param>
        /// <param name="replyTo">响应队列名</param>
        public void RedeliverToExchange(string exchangeName, string messageId, string messageTypeName, DateTime messageTimestamp, string messageBody, string routingKey, string correlationId = "", string replyTo = "")
        {
            if (string.IsNullOrEmpty(messageId))
            {
                throw new ArgumentNullException("messageId", "must not empty");
            }
            if (string.IsNullOrEmpty(messageTypeName))
            {
                throw new ArgumentNullException("messageTypeName", "must not empty");
            }
            if (messageTimestamp == DateTime.MinValue)
            {
                throw new ArgumentNullException("messageTimestamp", "must not empty");
            }
            if (string.IsNullOrEmpty(messageBody))
            {
                throw new ArgumentNullException("messageBody", "must not empty");
            }

            var body             = Serializer.GetBytes(messageBody);
            var envelopedMessage = new EnvelopedMessage(messageId,
                                                        messageTypeName,
                                                        messageTimestamp,
                                                        messageBody,
                                                        routingKey,
                                                        correlationId,
                                                        replyTo);

            try
            {
                RetryPolicy.Retry(() =>
                {
                    using (var channel = _conn.CreateChannel())
                    {
                        var properties          = channel.CreateBasicProperties();
                        properties.Persistent   = true;
                        properties.DeliveryMode = 2;
                        properties.ContentType  = Serializer.ContentType;
                        properties.MessageId    = messageId;
                        properties.Type         = messageTypeName;
                        properties.Timestamp    = new AmqpTimestamp(DateTime2UnixTime.ToUnixTime(messageTimestamp));
                        if (!string.IsNullOrEmpty(correlationId) && !string.IsNullOrEmpty(replyTo))
                        {
                            properties.CorrelationId = correlationId;
                            properties.ReplyTo       = replyTo;
                        }

                        channel.BasicPublish(exchange: exchangeName ?? string.Empty,
                                             routingKey: routingKey ?? string.Empty,
                                             mandatory: true,
                                             basicProperties: properties,
                                             body: body);
                        channel.Close();
                    }
                },
                                  cancelOnFailed: (retryCount, retryException) =>
                {
                    if (retryCount == 0)
                    {
                        _logger.Error($"Message [{messageTypeName}] \"{Serializer.GetString(body)}\" send to exchange \"{exchangeName}\", routing key={routingKey} failed.", retryException);
                    }
                    return(false);
                },
                                  retryCondition: ex => IOHelper.IsIOError(ex) || RabbitMQExceptionHelper.IsChannelError(ex),
                                  maxRetryCount: 1,
                                  retryTimeInterval: 1000);
                _logger.Info($"Message [{messageTypeName}] \"{Serializer.GetString(body)}\" send to exchange \"{exchangeName}\", routing key={routingKey} successful.");
            }
            catch (Exception ex)
            {
                var realEx = ex is TargetInvocationException ? ex.InnerException : ex;
                _logger.Error($"Message [{ messageTypeName}] \"{Serializer.GetString(body)}\" send to exchange \"{exchangeName}\", routing key={routingKey} failed.", realEx);
                throw new MessageSendFailedException(envelopedMessage, exchangeName, realEx);
            }
        }
Пример #5
0
        /// <summary>
        /// 重发到队列
        /// </summary>
        /// <param name="queueName">队列名</param>
        /// <param name="messageId">消息ID</param>
        /// <param name="messageTypeName">消息类型名</param>
        /// <param name="messageTimestamp">消息时间戳</param>
        /// <param name="messageBody">消息体</param>
        /// <param name="correlationId">关联ID</param>
        /// <param name="replyTo">响应队列名</param>
        public void RedeliverToQueue(string queueName, string messageId, string messageTypeName, DateTime messageTimestamp, string messageBody, string correlationId = "", string replyTo = "")
        {
            if (string.IsNullOrEmpty(queueName))
            {
                throw new ArgumentNullException("queueName", "must not empty");
            }
            if (string.IsNullOrEmpty(messageId))
            {
                throw new ArgumentNullException("messageId", "must not empty");
            }
            if (string.IsNullOrEmpty(messageTypeName))
            {
                throw new ArgumentNullException("messageTypeName", "must not empty");
            }
            if (messageTimestamp == DateTime.MinValue)
            {
                throw new ArgumentNullException("messageTimestamp", "must not empty");
            }
            if (string.IsNullOrEmpty(messageBody))
            {
                throw new ArgumentNullException("messageBody", "must not empty");
            }

            var body             = Serializer.GetBytes(messageBody);
            var routingKey       = queueName;
            var envelopedMessage = new EnvelopedMessage(messageId,
                                                        messageTypeName,
                                                        messageTimestamp,
                                                        messageBody,
                                                        routingKey,
                                                        correlationId,
                                                        replyTo);

            try
            {
                var context = new MessageSendingTransportationContext(string.Empty, new Dictionary <string, object> {
                    { MessagePropertyConstants.MESSAGE_ID, string.IsNullOrEmpty(messageId) ? Guid.NewGuid().ToString() : messageId },
                    { MessagePropertyConstants.MESSAGE_TYPE, messageTypeName },
                    { MessagePropertyConstants.TIMESTAMP, messageTimestamp },
                    { MessagePropertyConstants.CONTENT_TYPE, Serializer.ContentType },
                    { MessagePropertyConstants.PAYLOAD, Serializer.GetString(body) },
                    { MessagePropertyConstants.ROUTING_KEY, routingKey },
                    { MessagePropertyConstants.REPLY_TO, replyTo },
                    { MessagePropertyConstants.CORRELATION_ID, correlationId }
                });

                RetryPolicy.Retry(() =>
                {
                    using (var channel = _conn.CreateChannel())
                    {
                        var properties          = channel.CreateBasicProperties();
                        properties.Persistent   = true;
                        properties.DeliveryMode = 2;
                        properties.ContentType  = Serializer.ContentType;
                        properties.MessageId    = messageId;
                        properties.Type         = messageTypeName;
                        properties.Timestamp    = new AmqpTimestamp(DateTime2UnixTime.ToUnixTime(messageTimestamp));
                        if (!string.IsNullOrEmpty(correlationId) && !string.IsNullOrEmpty(replyTo))
                        {
                            properties.CorrelationId = correlationId;
                            properties.ReplyTo       = replyTo;
                        }

                        channel.BasicPublish(exchange: string.Empty,
                                             routingKey: routingKey,
                                             mandatory: true,
                                             basicProperties: properties,
                                             body: body);
                        channel.Close();
                    }
                },
                                  cancelOnFailed: (retryCount, retryException) =>
                {
                    if (retryCount == 0)
                    {
                        _logger.Error($"Message [{messageTypeName}] \"{Serializer.GetString(body)}\" send to queue \"{queueName}\" failed.", retryException);
                    }
                    return(false);
                },
                                  retryCondition: ex => IOHelper.IsIOError(ex) || RabbitMQExceptionHelper.IsChannelError(ex),
                                  maxRetryCount: 1,
                                  retryTimeInterval: 1000);
                if (_debugEnabled)
                {
                    _logger.Info($"Message [{messageTypeName}] \"{Serializer.GetString(body)}\" send to queue \"{queueName}\" successful.");
                }
            }
            catch (Exception ex)
            {
                var realEx = ex is TargetInvocationException ? ex.InnerException : ex;
                _logger.Error($"Message [{ messageTypeName}] \"{Serializer.GetString(body)}\" send to queue \"{queueName}\" failed.", realEx);
                throw new MessageSendFailedException(envelopedMessage, string.Empty, realEx);
            }
        }
Пример #6
0
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message">消息</param>
        /// <param name="routingKey">路由key</param>
        /// <returns></returns>
        public SendResult SendMessage(Message message, string routingKey)
        {
            if (_isRunning == 0)
            {
                return(new SendResult(SendStatus.Failed, null, "Couldn't send message when is not running."));
            }
            if (message == null)
            {
                return(new SendResult(SendStatus.Failed, null, "Message is null."));
            }
            if (!_topics.ContainsKey(message.Topic))
            {
                return(new SendResult(SendStatus.Failed, null, $"Topic {message.Topic} not registered."));
            }
            IRabbitMQChannel channel = null;

            try
            {
                var queueCount  = _topics[message.Topic];
                var queueId     = string.IsNullOrEmpty(routingKey) ? 0 : (Crc16.GetHashCode(routingKey) % queueCount);
                var messageId   = Guid.NewGuid().ToString();
                var createdTime = message.CreatedTime == DateTime.MinValue ? DateTime.Now : message.CreatedTime;
                if (_channelPool.TryDequeue(out Tuple <DateTime, IRabbitMQChannel> item))
                {
                    channel = item.Item2;
                }
                else
                {
                    channel = _amqpConnection.CreateModel();
                    channel.ConfirmSelect();
                }
                var properties = channel.CreateBasicProperties();
                properties.Persistent  = true;
                properties.ContentType = message.ContentType ?? string.Empty;
                properties.MessageId   = Guid.NewGuid().ToString();
                properties.Type        = message.Tag ?? string.Empty;
                properties.Timestamp   = new AmqpTimestamp(DateTime2UnixTime.ToUnixTime(createdTime));
                if (_delayedMessageEnabled && message.DelayedMilliseconds > 0)
                {
                    properties.Headers = new Dictionary <string, object>
                    {
                        { "x-delay", message.DelayedMilliseconds }
                    };
                }
                channel.BasicPublish(exchange: _delayedMessageEnabled && message.DelayedMilliseconds > 0 ? $"{message.Topic}-delayed" : message.Topic,
                                     routingKey: queueId.ToString(),
                                     mandatory: true,
                                     basicProperties: properties,
                                     body: message.Body);
                if (!channel.WaitForConfirms(_sendMsgTimeout, out bool timedOut))
                {
                    return(new SendResult(timedOut ? SendStatus.Timeout : SendStatus.Failed, null, "Wait for confirms failed."));
                }
                var storeResult = new MessageStoreResult(messageId, message.Code, message.Topic, queueId, createdTime, message.Tag);
                return(new SendResult(SendStatus.Success, storeResult, null));
            }
            catch (Exception ex)
            {
                throw new System.IO.IOException("Send message has exception.", ex);
            }
            finally
            {
                if (channel != null)
                {
                    _channelPool.Enqueue(new Tuple <DateTime, IRabbitMQChannel>(DateTime.Now, channel));
                }
            }
        }
Пример #7
0
        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);
                    }
                }
            }
        }
Пример #8
0
        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);
                    }
                }
            }
        }
Пример #9
0
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message">消息</param>
        public void SendMessage <T>(Envelope <T> message) where T : class
        {
            if (message == null || message.Body == null)
            {
                throw new ArgumentNullException("message");
            }
            var body            = Serializer.Serialize(message.Body);
            var messageTypeName = MessageTypeAttribute.GetTypeName(message.Body.GetType());
            var routingKey      = string.Empty;

            if (_publishToExchange)
            {
                uint routingKeyHashCode = 0;
                if (!uint.TryParse(message.RoutingKey, out routingKeyHashCode))
                {
                    routingKeyHashCode = (uint)message.RoutingKey.GetHashCode();
                }
                routingKey = (routingKeyHashCode % _publishToExchangeQueueCount).ToString();
            }
            else
            {
                routingKey = message.RoutingKey == null ? string.Empty : message.RoutingKey;
            }
            var envelopedMessage = new EnvelopedMessage(message.MessageId,
                                                        messageTypeName,
                                                        message.Timestamp,
                                                        Serializer.GetString(body),
                                                        routingKey,
                                                        string.Empty,
                                                        string.Empty);

            var context = new MessageSendingTransportationContext(ExchangeName, new Dictionary <string, object> {
                { MessagePropertyConstants.MESSAGE_ID, string.IsNullOrEmpty(message.MessageId) ? Guid.NewGuid().ToString() : message.MessageId },
                { MessagePropertyConstants.MESSAGE_TYPE, messageTypeName },
                { MessagePropertyConstants.TIMESTAMP, message.Timestamp },
                { MessagePropertyConstants.CONTENT_TYPE, Serializer.ContentType },
                { MessagePropertyConstants.PAYLOAD, Serializer.GetString(body) },
                { MessagePropertyConstants.ROUTING_KEY, routingKey }
            });

            try
            {
                TriggerOnMessageSent(new MessageSentEventArgs(this.GetSenderType(), context));
                if (!IsRunning())
                {
                    throw new ObjectDisposedException(nameof(PubsubSender));
                }
                IncreaseRetryingMessageCount();

                RetryPolicy.Retry(() =>
                {
                    using (var channel = _conn.CreateChannel())
                    {
                        var properties          = channel.CreateBasicProperties();
                        properties.Persistent   = true;
                        properties.DeliveryMode = 2;
                        properties.ContentType  = Serializer.ContentType;
                        properties.MessageId    = message.MessageId;
                        properties.Type         = messageTypeName;
                        properties.Timestamp    = new AmqpTimestamp(DateTime2UnixTime.ToUnixTime(message.Timestamp));
                        if (_confirmEnabled)
                        {
                            channel.ConfirmSelect();
                        }
                        channel.BasicPublish(exchange: ExchangeName,
                                             routingKey: routingKey,
                                             mandatory: _atLeastMatchOneQueue,
                                             basicProperties: properties,
                                             body: body);
                        if (_confirmEnabled && !channel.WaitForConfirms())
                        {
                            throw new Exception("Wait for confirm after sending message failed");
                        }
                    }
                },
                                  cancelOnFailed: (retryCount, retryException) =>
                {
                    return(false);
                },
                                  retryCondition: ex => IOHelper.IsIOError(ex) || RabbitMQExceptionHelper.IsChannelError(ex),
                                  retryTimeInterval: 1000,
                                  maxRetryCount: _maxRetryCount);
                TriggerOnMessageSendingSucceeded(new MessageSendingSucceededEventArgs(this.GetSenderType(), context));
            }
            catch (Exception ex)
            {
                var realEx = ex is TargetInvocationException ? ex.InnerException : ex;
                context.LastException = realEx;
                TriggerOnMessageSendingFailed(new MessageSendingFailedEventArgs(this.GetSenderType(), context));
                throw new MessageSendFailedException(envelopedMessage, ExchangeName, realEx);
            }
            finally
            {
                DecreaseRetryingMessageCount();
            }
        }
Пример #10
0
        /// <summary>
        /// 发送请求
        /// </summary>
        /// <param name="message">消息</param>
        /// <param name="methodName">方法名</param>
        /// <param name="correlationId">关联ID</param>
        public void SendRequest <T>(Envelope <T> message, string methodName, string correlationId) where T : class
        {
            if (message == null || message.Body == null)
            {
                throw new ArgumentNullException("message");
            }
            var queueName         = _disableQueuePrefix ? methodName : $"rpc.{methodName}";
            var callbackQueueName = $"{queueName}.callback";
            var body             = Serializer.Serialize(message.Body);
            var messageTypeName  = MessageTypeAttribute.GetTypeName(message.Body.GetType());
            var routingKey       = string.IsNullOrEmpty(ExchangeName) ? queueName : methodName;
            var envelopedMessage = new EnvelopedMessage(message.MessageId,
                                                        messageTypeName,
                                                        message.Timestamp,
                                                        Serializer.GetString(body),
                                                        routingKey,
                                                        correlationId,
                                                        callbackQueueName);

            var context = new MessageSendingTransportationContext(ExchangeName, new Dictionary <string, object> {
                { MessagePropertyConstants.MESSAGE_ID, string.IsNullOrEmpty(message.MessageId) ? Guid.NewGuid().ToString() : message.MessageId },
                { MessagePropertyConstants.MESSAGE_TYPE, messageTypeName },
                { MessagePropertyConstants.TIMESTAMP, message.Timestamp },
                { MessagePropertyConstants.CONTENT_TYPE, Serializer.ContentType },
                { MessagePropertyConstants.PAYLOAD, Serializer.GetString(body) },
                { MessagePropertyConstants.ROUTING_KEY, routingKey },
                { MessagePropertyConstants.REPLY_TO, callbackQueueName },
                { MessagePropertyConstants.CORRELATION_ID, correlationId }
            });

            TriggerOnMessageSent(new MessageSentEventArgs(this.GetSenderType(), context));
            try
            {
                if (!IsRunning())
                {
                    throw new ObjectDisposedException(nameof(RpcClient));
                }
                IncreaseRetryingMessageCount();

                RetryPolicy.Retry(() =>
                {
                    using (var channel = _conn.CreateChannel())
                    {
                        var properties           = channel.CreateBasicProperties();
                        properties.Persistent    = true;
                        properties.DeliveryMode  = 2;
                        properties.ContentType   = Serializer.ContentType;
                        properties.MessageId     = message.MessageId;
                        properties.Type          = messageTypeName;
                        properties.Timestamp     = new AmqpTimestamp(DateTime2UnixTime.ToUnixTime(message.Timestamp));
                        properties.ReplyTo       = callbackQueueName;
                        properties.CorrelationId = correlationId;
                        if (_confirmEnabled)
                        {
                            channel.ConfirmSelect();
                        }
                        channel.BasicPublish(exchange: ExchangeName,
                                             routingKey: routingKey,
                                             mandatory: true,
                                             basicProperties: properties,
                                             body: body);
                        if (_confirmEnabled && !channel.WaitForConfirms())
                        {
                            throw new Exception("Wait for confirm after sending message failed");
                        }
                    }
                },
                                  cancelOnFailed: (retryCount, retryException) =>
                {
                    return(false);
                },
                                  retryCondition: ex => IOHelper.IsIOError(ex) || RabbitMQExceptionHelper.IsChannelError(ex),
                                  retryTimeInterval: 1000,
                                  maxRetryCount: _maxRetryCount);
                TriggerOnMessageSendingSucceeded(new MessageSendingSucceededEventArgs(this.GetSenderType(), context));
            }
            catch (Exception ex)
            {
                var realEx = ex is TargetInvocationException ? ex.InnerException : ex;
                context.LastException = realEx;
                TriggerOnMessageSendingFailed(new MessageSendingFailedEventArgs(this.GetSenderType(), context));
                throw new MessageSendFailedException(envelopedMessage, ExchangeName, realEx);
            }
            finally
            {
                DecreaseRetryingMessageCount();
            }
        }