예제 #1
0
        /// <summary>
        /// 通知Mq消息处理结果
        /// </summary>
        /// <param name="ea"></param>
        /// <param name="currentConsumerLoopChannel"></param>
        /// <param name="consumeHandleResult"></param>
        /// <param name="storedException"></param>
        private void AcknowledgeMessage(BasicDeliverEventArgs ea, IModel currentConsumerLoopChannel, ConsumeHandleResult consumeHandleResult, object storedException = null)
        {
            try
            {
                switch (consumeHandleResult)
                {
                case ConsumeHandleResult.Act:
                    currentConsumerLoopChannel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
                    //重试消息处理逻辑
                    if (ea.BasicProperties.MessageId.IsNotNullOrWhitespace())
                    {
                        var messageId = ea.BasicProperties.MessageId;
                        var consumerErrorMessageRepository = ServiceProvider.GetService <IConsumerErrorMessageStore>();
                        consumerErrorMessageRepository.DeleteAsync(messageId.SafeToObjectId()).Wait();
                    }
                    break;

                case ConsumeHandleResult.ActAndMoveToErrorQueue:
                    currentConsumerLoopChannel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
                    //重试消息处理逻辑
                    if (ea.BasicProperties.MessageId.IsNotNullOrWhitespace())
                    {
                        var messageId = ea.BasicProperties.MessageId;
                        var consumerErrorMessageRepository = ServiceProvider.GetService <IConsumerErrorMessageStore>();
                        var message = consumerErrorMessageRepository.GetByIdAsync(messageId.SafeToObjectId()).Result;
                        message.ProcessTimes += 1;    //已重试次数+1

                        var originalBodyMessage      = Encoding.UTF8.GetString(ea.Body);
                        var orignalBodyMessageObject = BsonSerializer.Deserialize <BsonDocument>(originalBodyMessage);
                        var update = Builders <ConsumerErrorMessage> .Update
                                     .Set(x => x.ProcessTimes, message.ProcessTimes)
                                     .Set(x => x.RetryTime, DateTime.Now)
                                     .Set(x => x.RetryNow, 0)
                                     .Set(x => x.RetryLock, null)
                                     .Set(x => x.Exception, storedException.ToBsonDocument())
                                     .Set(x => x.LastedOriginalMessage, orignalBodyMessageObject)
                                     .Set(x => x.NextRetryTime, DateTime.Now.AddMinutes(Math.Pow(_retryTimeSpanBaseSeconds, message.ProcessTimes)));//计算下次重试时间

                        consumerErrorMessageRepository.UpdateAsync(Builders <ConsumerErrorMessage> .Filter.Eq(x => x.Sysid, messageId.SafeToObjectId()), update).Wait();
                    }
                    else
                    {
                        //如当前Consumer开启MoveToErrorQueue则推送到错误队列
                        if (MoveToErrorQueueWhenErrorOccured)
                        {
                            var originalBodyMessage      = Encoding.UTF8.GetString(ea.Body);
                            var orignalBodyMessageObject = JObject.Parse(originalBodyMessage);

                            var errorMessageModel = new
                            {
                                RoutingKey     = ea.RoutingKey,
                                Exchange       = ea.Exchange,
                                Logged         = DateTime.Now,
                                OrignalMessage = orignalBodyMessageObject,
                                Exception      = storedException,
                                CanRetry       = MessageCanRetryWhenErrorOccured ? 1 : 0,
                                ProcessTimes   = 1,
                                NextRetryTime  = DateTime.Now.AddMinutes(Math.Pow(_retryTimeSpanBaseSeconds, 1))   //计算第二次的重试时间
                            };

                            var uncompressedMessage = MessageHelper.GetMessage(JsonConvert.SerializeObject(errorMessageModel, new JsonSerializerSettings()
                            {
                                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                            }), Encoding.UTF8);
                            var sendMessage = MessageHelper.CompressMessage(uncompressedMessage, CompressionTypes.None);

                            RecordConsumerError(ea.RoutingKey, sendMessage);
                        }
                    }
                    break;

                case ConsumeHandleResult.Reject:
                    currentConsumerLoopChannel.BasicReject(ea.DeliveryTag, true);    //拒绝消息, 重新插入队列
                    break;

                default:
                    break;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"MessageConsume消息消费发生异常之后, 在处理异常的过程中再次发生错误, EXType:{ex.GetType().FullName} 错误详细信息: {ex.FullMessage()}");
            }
        }
예제 #2
0
        /// <summary>
        /// 消息的接收事件处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ea"></param>
        private void ConsumerReceiveHandler(object sender, BasicDeliverEventArgs ea)
        {
            StopwatchAction((stopwatch) =>
            {
                //If the channel is closed, directly return no need to handle;
                var currentConsumerLoopChannel = (sender as IBasicConsumer)?.Model;
                if (currentConsumerLoopChannel == null || currentConsumerLoopChannel.IsClosed)
                {
                    return;
                }

                if (CancellationToken.IsCancellationRequested)
                {
                    StopConsume();//释放本地对象
                    return;
                }

                ConsumeHandleResult consumeHandleResult = ConsumeHandleResult.Act;
                try
                {
                    var bodyMessage = Encoding.UTF8.GetString(ea.Body);
                    var cts         = new CancellationTokenSource(HostingEnvironment?.IsDevelopment() ?? false ? TimeSpan.FromMinutes(30) : TimeSpan.FromMinutes(30));
                    using (var serviceScope = ServiceProvider.CreateScope())
                    {
                        ConsumerAsync(ea, bodyMessage, serviceScope.ServiceProvider).Wait(cts.Token);
                    }
                    consumeHandleResult = ConsumeHandleResult.Act;
                    AcknowledgeMessage(ea, currentConsumerLoopChannel, consumeHandleResult);
                }
                catch (AggregateException ex)
                {
                    _logger.LogError(ex, $"消息消费时出现异常,将推送到消费错误队列进行人工处理, 详细错误:{ex.FullMessage()}");
                    consumeHandleResult = ConsumeHandleResult.ActAndMoveToErrorQueue;
                    var storedException = ex.InnerExceptions.Select(x => new { Message = x.FullMessage(), StackTrace = x.FullStacktrace(), ExType = x.FullExType() }).ToList();
                    AcknowledgeMessage(ea, currentConsumerLoopChannel, consumeHandleResult, new { Errors = storedException });
                }
                catch (TaskCanceledException ex)
                {
                    consumeHandleResult = ConsumeHandleResult.ActAndMoveToErrorQueue;
                    _logger.LogError(ex, $"消息消费出现[TaskCanceledException]异常,并将推送到消费错误队列进行人工处理, 详细错误:{ex.FullMessage()}");
                    var storedException = new { Message = ex.FullMessage(), StackTrace = ex.FullStacktrace(), ExType = ex.FullExType() };
                    AcknowledgeMessage(ea, currentConsumerLoopChannel, consumeHandleResult, storedException);
                }
                catch (OperationCanceledException ex)
                {
                    consumeHandleResult = ConsumeHandleResult.ActAndMoveToErrorQueue;
                    _logger.LogError(ex, $"消息消费超时OperationCanceledException(超时时间120秒), 并将推送到消费错误队列进行人工核查处理, 详细错误:{ex.FullMessage()}");
                    var storedException = new { Message = ex.FullMessage(), StackTrace = ex.FullStacktrace(), ExType = ex.FullExType() };
                    AcknowledgeMessage(ea, currentConsumerLoopChannel, consumeHandleResult, storedException);
                }
                catch (Exception ex)
                {
                    consumeHandleResult = ConsumeHandleResult.ActAndMoveToErrorQueue;
                    _logger.LogError(ex, $"消息消费出现异常[{ex.GetType().FullName}],并将推送到消费错误队列进行人工处理, 详细错误:{ex.FullMessage()}");
                    var storedException = new { Message = ex.FullMessage(), StackTrace = ex.FullStacktrace(), ExType = ex.FullExType() };
                    AcknowledgeMessage(ea, currentConsumerLoopChannel, consumeHandleResult, storedException);
                    //only no particular exception have the retry
                }
            }, SessionName + " consumer message used:{0} ms", sw =>
            {
                //todo: 耗时分析
            });
        }