private void HandleMessage(ConsumingMessage consumingMessage) { if (_stoped) { return; } if (consumingMessage == null) { return; } if (consumingMessage.ProcessQueue.IsDropped) { return; } try { _messageHandler.Handle(consumingMessage.Message, new MessageContext(currentQueueMessage => RemoveHandledMessage(consumingMessage))); } catch (Exception ex) { //TODO,目前,对于消费失败(遇到异常)的消息,我们先记录错误日志,然后将该消息放入本地内存的重试队列; //放入重试队列后,会定期对该消息进行重试,重试队列中的消息会每隔1s被取出一个来重试。 //通过这样的设计,可以确保消费有异常的消息不会被认为消费已成功,也就是说不会从ProcessQueue中移除; //但不影响该消息的后续消息的消费,该消息的后续消息仍然能够被消费,但是ProcessQueue的消费位置,即滑动门不会向前移动了; //因为只要该消息一直消费遇到异常,那就意味着该消息所对应的queueOffset不能被认为已消费; //而我们发送到broker的是当前最小的已被成功消费的queueOffset,所以broker上记录的当前queue的消费位置(消费进度)不会往前移动, //直到当前失败的消息消费成功为止。所以,如果我们重启了消费者服务器,那下一次开始消费的消费位置还是从当前失败的位置开始, //即便当前失败的消息的后续消息之前已经被消费过了;所以应用需要对每个消息的消费都要支持幂等,不过enode对所有的command和event的处理都支持幂等; //以后,我们会在broker上支持重试队列,然后我们可以将消费失败的消息发回到broker上的重试队列,发回到broker上的重试队列成功后, //就可以让当前queue的消费位置往前移动了。 LogMessageHandlingException(consumingMessage, ex); _messageRetryQueue.Add(consumingMessage); } }
private void RemoveHandledMessage(ConsumingMessage consumingMessage) { ConsumingMessage consumedMessage; if (_handlingMessageDict.TryRemove(consumingMessage.Message.MessageOffset, out consumedMessage)) { consumedMessage.ProcessQueue.RemoveMessage(consumedMessage.Message); } }
private void RemoveHandledMessage(ConsumingMessage consumingMessage) { ConsumingMessage consumedMessage; if (_handlingMessageDict.TryRemove(consumingMessage.Message.RoutingKey, out consumedMessage)) { _finishedMessageTag.Enqueue(consumingMessage.Message.DeliveryTag); } }
private void LogMessageHandlingException(ConsumingMessage consumingMessage, Exception exception) { _logger.Error(string.Format( "Message handling has exception, message info:[topic={0}, queueId={1}, queueOffset={2}, storedTime={3}, group={4}]", consumingMessage.Message.Topic, consumingMessage.Message.QueueId, consumingMessage.Message.QueueOffset, consumingMessage.Message.StoredTime, GroupName), exception); }
private void LogMessageHandlingException(ConsumingMessage consumingMessage, Exception exception) { _logger.Error(string.Format( "Message handling has exception, message info:[messageId:{0}, topic:{1}, queueId:{2}, queueOffset:{3}, createdTime:{4}, storedTime:{5}, consumerGroup:{6}]", consumingMessage.Message.MessageId, consumingMessage.Message.Topic, consumingMessage.Message.QueueId, consumingMessage.Message.QueueOffset, consumingMessage.Message.CreatedTime, consumingMessage.Message.StoredTime, GroupName), exception); }
public void RemoveMessage(ConsumingMessage consumingMessage) { lock (_lockObj) { if (_messageDict.Remove(consumingMessage.Message.QueueOffset)) { if (_messageDict.Keys.IsNotEmpty()) { _consumedQueueOffset = _messageDict.Keys.First() - 1; } else { _consumedQueueOffset = _maxQueueOffset; } _messageCount--; } } }
private void RemoveHandledMessage(ConsumingMessage consumedMessage) { consumedMessage.ProcessQueue.RemoveMessage(consumedMessage.Message); }
private void ProcessPullResponse(PullRequest pullRequest, RemotingResponse remotingResponse) { if (remotingResponse == null) { _logger.ErrorFormat("Pull message response is null, pullRequest:{0}", pullRequest); SchedulePullRequest(pullRequest); return; } if (remotingResponse.Code == -1) { _logger.ErrorFormat("Pull message failed, pullRequest:{0}, errorMsg:{1}", pullRequest, Encoding.UTF8.GetString(remotingResponse.Body)); SchedulePullRequest(pullRequest); return; } if (remotingResponse.Code == (short)PullStatus.Found) { var messages = DecodeMessages(pullRequest, remotingResponse.Body); if (messages.Count() > 0) { var filterMessages = messages.Where(x => IsQueueMessageMatchTag(x, pullRequest.Tags)); pullRequest.ProcessQueue.AddMessages(filterMessages); foreach (var message in filterMessages) { var consumingMessage = new ConsumingMessage(message, pullRequest.ProcessQueue); if (Setting.MessageHandleMode == MessageHandleMode.Sequential) { _consumingMessageQueue.Add(consumingMessage); } else { Task.Factory.StartNew(HandleMessage, consumingMessage); } } pullRequest.NextConsumeOffset = messages.Last().QueueOffset + 1; } } else if (remotingResponse.Code == (short)PullStatus.NextOffsetReset) { var newOffset = BitConverter.ToInt64(remotingResponse.Body, 0); var oldOffset = pullRequest.NextConsumeOffset; pullRequest.NextConsumeOffset = newOffset; _logger.InfoFormat("Reset queue next consume offset. topic:{0}, queueId:{1}, old offset:{2}, new offset:{3}", pullRequest.MessageQueue.Topic, pullRequest.MessageQueue.QueueId, oldOffset, newOffset); } else if (remotingResponse.Code == (short)PullStatus.NoNewMessage) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("No new message found, pullRequest:{0}", pullRequest); } } else if (remotingResponse.Code == (short)PullStatus.Ignored) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Pull request was ignored, pullRequest:{0}", pullRequest); } return; } else if (remotingResponse.Code == (short)PullStatus.BrokerIsCleaning) { Thread.Sleep(5000); } //Schedule the next pull request. SchedulePullRequest(pullRequest); }
private void ProcessPullResponse(PullRequest pullRequest, RemotingResponse remotingResponse) { if (remotingResponse == null) { _logger.ErrorFormat("Pull message response is null, pullRequest:{0}", pullRequest); SchedulePullRequest(pullRequest); return; } if (remotingResponse.Code == -1) { _logger.ErrorFormat("Pull message failed, pullRequest:{0}, errorMsg:{1}", pullRequest, Encoding.UTF8.GetString(remotingResponse.Body)); SchedulePullRequest(pullRequest); return; } if (remotingResponse.Code == (short)PullStatus.Found) { var messages = DecodeMessages(pullRequest, remotingResponse.Body); if (messages.Count() > 0) { var filterMessages = messages.Where(x => IsQueueMessageMatchTag(x, pullRequest.Tags)); pullRequest.ProcessQueue.AddMessages(filterMessages); foreach (var message in filterMessages) { var consumingMessage = new ConsumingMessage(message, pullRequest.ProcessQueue); if (Setting.MessageHandleMode == MessageHandleMode.Sequential) { _consumingMessageQueue.Add(consumingMessage); } else { Task.Factory.StartNew(HandleMessage, consumingMessage); } } pullRequest.NextConsumeOffset = messages.Last().QueueOffset + 1; } } else if (remotingResponse.Code == (short)PullStatus.NextOffsetReset) { var newOffset = BitConverter.ToInt64(remotingResponse.Body, 0); var oldOffset = pullRequest.NextConsumeOffset; pullRequest.NextConsumeOffset = newOffset; pullRequest.ProcessQueue.Reset(); _logger.InfoFormat("Reset queue next consume offset. topic:{0}, queueId:{1}, old offset:{2}, new offset:{3}", pullRequest.MessageQueue.Topic, pullRequest.MessageQueue.QueueId, oldOffset, newOffset); } else if (remotingResponse.Code == (short)PullStatus.NoNewMessage) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("No new message found, pullRequest:{0}", pullRequest); } } else if (remotingResponse.Code == (short)PullStatus.Ignored) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Pull request was ignored, pullRequest:{0}", pullRequest); } return; } else if (remotingResponse.Code == (short)PullStatus.BrokerIsCleaning) { Thread.Sleep(5000); } //Schedule the next pull request. SchedulePullRequest(pullRequest); }
private void LogMessageHandlingException(ConsumingMessage consumingMessage, Exception exception) { _logger.Error(string.Format( "Message handling has exception, message info:[messageOffset={0}, topic={1}, queueId={2}, queueOffset={3}, storedTime={4}, consumerId={5}, group={6}]", consumingMessage.Message.MessageOffset, consumingMessage.Message.Topic, consumingMessage.Message.QueueId, consumingMessage.Message.QueueOffset, consumingMessage.Message.StoredTime, Id, GroupName), exception); }
private void HandleMessage(ConsumingMessage consumingMessage) { if (_stoped) return; if (consumingMessage == null) return; if (consumingMessage.ProcessQueue.IsDropped) return; try { _messageHandler.Handle(consumingMessage.Message, new MessageContext(currentQueueMessage => RemoveHandledMessage(consumingMessage))); } catch (Exception ex) { //TODO,目前,对于消费失败(遇到异常)的消息,我们先记录错误日志,然后将该消息放入本地内存的重试队列; //放入重试队列后,会定期对该消息进行重试,重试队列中的消息会每隔1s被取出一个来重试。 //通过这样的设计,可以确保消费有异常的消息不会被认为消费已成功,也就是说不会从ProcessQueue中移除; //但不影响该消息的后续消息的消费,该消息的后续消息仍然能够被消费,但是ProcessQueue的消费位置,即滑动门不会向前移动了; //因为只要该消息一直消费遇到异常,那就意味着该消息所对应的queueOffset不能被认为已消费; //而我们发送到broker的是当前最小的已被成功消费的queueOffset,所以broker上记录的当前queue的消费位置(消费进度)不会往前移动, //直到当前失败的消息消费成功为止。所以,如果我们重启了消费者服务器,那下一次开始消费的消费位置还是从当前失败的位置开始, //即便当前失败的消息的后续消息之前已经被消费过了;所以应用需要对每个消息的消费都要支持幂等,不过enode对所有的command和event的处理都支持幂等; //以后,我们会在broker上支持重试队列,然后我们可以将消费失败的消息发回到broker上的重试队列,发回到broker上的重试队列成功后, //就可以让当前queue的消费位置往前移动了。 LogMessageHandlingException(consumingMessage, ex); _messageRetryQueue.Add(consumingMessage); } }