Ejemplo n.º 1
0
        /// <summary>
        /// 订阅消息(同一类消息可以重复订阅)
        /// 作者:郭明
        /// 日期:2017年4月3日
        /// </summary>
        /// <typeparam name="TD"></typeparam>
        /// <typeparam name="TH"></typeparam>
        /// <param name="EventTypeName">消息类型名称</param>
        /// <returns></returns>
        public IEventBus RegisterBatch <TD, TH>(string QueueName, string EventTypeName = "", int BatchSize = 50, CancellationToken cancellationToken = default(CancellationToken))
            where TD : class
            where TH : IEventBatchHandler <TD>
        {
            var queueName   = string.IsNullOrEmpty(QueueName) ? typeof(TH).FullName : QueueName;
            var routeKey    = string.IsNullOrEmpty(EventTypeName) ? typeof(TD).FullName : EventTypeName;
            var eventAction = _lifetimeScope.GetService(typeof(TH)) as IEventBatchHandler <TD>;

            if (eventAction == null)
            {
                eventAction = System.Activator.CreateInstance(typeof(TH)) as IEventBatchHandler <TD>;
            }
            var persistentConnection = _receiverLoadBlancer.Lease();

            if (!persistentConnection.IsConnected)
            {
                persistentConnection.TryConnect();
            }

            for (int parallelism = 0; parallelism < _reveiverMaxDegreeOfParallelism; parallelism++)
            {
                try
                {
                    var _channel = persistentConnection.GetConsumer();


                    //direct fanout topic
                    _channel.ExchangeDeclare(_exchange, _exchangeType, true, false, null);
                    //在MQ上定义一个持久化队列,如果名称相同不会重复创建
                    _channel.QueueDeclare(queueName, true, false, false, null);
                    //绑定交换器和队列
                    _channel.QueueBind(queueName, _exchange, routeKey);
                    _channel.QueueBind(queueName, _exchange, queueName);
                    //输入1,那如果接收一个消息,但是没有应答,则客户端不会收到下一个消息
                    _channel.BasicQos(0, (ushort)BatchSize, false);

                    Task.Run(async() =>
                    {
                        while (true)
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            try
                            {
                                var batchPool            = new List <(string MessageId, BasicGetResult ea)>();
                                var batchLastDeliveryTag = 0UL;

                                #region batch Pull
                                for (var i = 0; i < BatchSize; i++)
                                {
                                    var ea = _channel.BasicGet(queueName, false);

                                    if (ea != null)
                                    {
                                        var MessageId = ea.BasicProperties.MessageId;

                                        if (string.IsNullOrEmpty(MessageId))
                                        {
                                            batchPool.Add((Guid.NewGuid().ToString("N"), ea));
                                        }
                                        else
                                        {
                                            batchPool.Add((ea.BasicProperties.MessageId, ea));
                                        }

                                        batchLastDeliveryTag = ea.DeliveryTag;
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }

                                #endregion

                                //队列不为空
                                if (batchPool.Count > 0)
                                {
                                    using (var receiveTracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Received"))
                                    {
                                        var basicGetResults  = batchPool.Select(a => a.ea).ToArray();
                                        var Messages         = new EventResponse[basicGetResults.Length];
                                        var handlerSuccess   = false;
                                        var handlerException = default(Exception);

                                        try
                                        {
                                            for (int i = 0; i < basicGetResults.Length; i++)
                                            {
                                                var ea        = basicGetResults[i];
                                                var MessageId = string.IsNullOrEmpty(ea.BasicProperties.MessageId) ? Guid.NewGuid().ToString("N") : ea.BasicProperties.MessageId;
                                                var TraceId   = MessageId;
                                                var EventId   = -1L;

                                                if (ea.BasicProperties.Headers != null)
                                                {
                                                    #region 获取 eventId
                                                    if (ea.BasicProperties.Headers.ContainsKey("x-eventId"))
                                                    {
                                                        try
                                                        {
                                                            if (!long.TryParse(System.Text.Encoding.UTF8.GetString(ea.BasicProperties.Headers["x-eventId"] as byte[]), out EventId))
                                                            {
                                                                //
                                                            }
                                                        }
                                                        catch (Exception ex)
                                                        {
                                                            _logger.LogError(ex, ex.Message);
                                                        }
                                                    }
                                                    #endregion

                                                    #region 获取 traceid
                                                    if (!ea.BasicProperties.Headers.ContainsKey("x-traceId"))
                                                    {
                                                        try
                                                        {
                                                            TraceId = System.Text.Encoding.UTF8.GetString(ea.BasicProperties.Headers["traceId"] as byte[]);
                                                        }
                                                        catch (Exception ex)
                                                        {
                                                            _logger.LogError(ex, ex.Message);
                                                        }
                                                    }
                                                    #endregion
                                                }

                                                using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP BasicGet"))
                                                {
                                                    tracer.SetComponent(_compomentName);
                                                    tracer.SetTag("queueName", queueName);
                                                    tracer.SetTag("x-messageId", MessageId);
                                                    tracer.SetTag("x-eventId", EventId);
                                                    tracer.SetTag("x-traceId", TraceId);

                                                    Messages[i] = new EventResponse()
                                                    {
                                                        EventId    = EventId,
                                                        MessageId  = MessageId,
                                                        TraceId    = TraceId,
                                                        Headers    = ea.BasicProperties.Headers ?? new Dictionary <string, object>(),
                                                        RouteKey   = routeKey,
                                                        QueueName  = queueName,
                                                        BodySource = Encoding.UTF8.GetString(ea.Body),
                                                        Body       = default(TD),
                                                    };

                                                    #region 设置 header
                                                    if (!Messages[i].Headers.ContainsKey("x-exchange"))
                                                    {
                                                        Messages[i].Headers.Add("x-exchange", _exchange);
                                                    }

                                                    if (!Messages[i].Headers.ContainsKey("x-exchange-type"))
                                                    {
                                                        Messages[i].Headers.Add("x-exchange-type", _exchangeType);
                                                    }
                                                    #endregion

                                                    #region 设置body
                                                    try
                                                    {
                                                        Messages[i].Body = JsonConvert.DeserializeObject <TD>(Messages[i].BodySource);
                                                        _logger.LogInformation(Messages[i].BodySource);
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        tracer.SetError();
                                                        _logger.LogError(ex, ex.Message);
                                                    }
                                                    #endregion
                                                }
                                            }


                                            if (Messages != null && Messages.Any())
                                            {
                                                using (var executeTracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Execute"))
                                                {
                                                    executeTracer.SetComponent(_compomentName);

                                                    handlerSuccess = await _receiverPolicy.ExecuteAsync(async(handlerCancellationToken) =>
                                                    {
                                                        return(await eventAction.Handle(Messages.Select(a => (TD)a.Body).ToArray(), Messages.Select(a => (Dictionary <string, object>)a.Headers).ToArray(), handlerCancellationToken));
                                                    }, cancellationToken);

                                                    if (handlerSuccess)
                                                    {
                                                        #region 消息处理成功
                                                        if (_subscribeAckHandler != null && Messages.Length > 0)
                                                        {
                                                            _subscribeAckHandler(Messages);
                                                        }

                                                        //确认消息被处理
                                                        _channel.BasicAck(batchLastDeliveryTag, true);

                                                        #endregion
                                                    }
                                                    else
                                                    {
                                                        executeTracer.SetError();
                                                    }
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            _logger.LogError(ex, ex.Message);
                                            receiveTracer.SetError();
                                            handlerException = ex;
                                        }
                                        finally
                                        {
                                            if (!handlerSuccess)
                                            {
                                                #region 消息处理失败
                                                var requeue = true;
                                                try
                                                {
                                                    if (_subscribeNackHandler != null && Messages.Length > 0)
                                                    {
                                                        requeue = await _subscribeNackHandler((Messages, handlerException));
                                                    }
                                                }
                                                catch (Exception innterEx)
                                                {
                                                    _logger.LogError(innterEx.Message, innterEx);
                                                }

                                                _channel.BasicNack(batchLastDeliveryTag, true, requeue);

                                                #endregion
                                            }
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError(ex.Message, ex);
                            }

                            System.Threading.Thread.Sleep(1);
                        }
                    });
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, ex.Message);
                }
            }

            return(this);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 订阅消息(同一类消息可以重复订阅)
        /// 作者:郭明
        /// 日期:2017年4月3日
        /// </summary>
        /// <typeparam name="TD"></typeparam>
        /// <typeparam name="TH"></typeparam>
        /// <param name="QueueName"></param>
        /// <param name="EventTypeName"></param>
        /// <param name="BatchSize"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public IEventBus RegisterBatch <TD, TH>(string QueueName, string EventTypeName = "", int BatchSize = 50, CancellationToken cancellationToken = default(CancellationToken))
            where TD : class
            where TH : IEventBatchHandler <TD>
        {
            var persistentConnection = _receiveLoadBlancer.Lease();
            var queueName            = string.IsNullOrEmpty(QueueName) ? typeof(TH).FullName : QueueName;
            var routeKey             = string.IsNullOrEmpty(EventTypeName) ? typeof(TD).FullName : EventTypeName;
            var eventAction          = _lifetimeScope.GetService(typeof(TH)) as IEventBatchHandler <TD>;

            if (eventAction == null)
            {
                eventAction = System.Activator.CreateInstance(typeof(TH)) as IEventBatchHandler <TD>;
            }

            System.Threading.Tasks.Task.Run(async() =>
            {
                IConsumer <string, string> consumer = null;

                try
                {
                    consumer = persistentConnection.GetConsumer();
                    consumer.Subscribe(routeKey);

                    while (!cancellationToken.IsCancellationRequested)
                    {
                        try
                        {
                            var handlerSuccess   = false;
                            var handlerException = default(Exception);
                            var eas      = consumer.ConsumeBatch(TimeSpan.FromMilliseconds(100), BatchSize, cancellationToken).ToArray();
                            var Messages = new EventResponse[eas.Count()];

                            if (Messages.Length > 0)
                            {
                                _logger.LogInformation($"customer {consumer.Name} got {Messages.Length} messages on subject {routeKey}.");
                            }
                            else
                            {
                                _logger.LogInformation($"customer {consumer.Name} did not get the message of topic {routeKey}.");
                                await System.Threading.Tasks.Task.Delay(50);
                                continue;
                            }

                            try
                            {
                                #region 批量格式化消息
                                for (int j = 0; j < eas.Length; j++)
                                {
                                    var ea = eas[j];

                                    // 消息队列空
                                    if (ea.IsPartitionEOF)
                                    {
                                        _logger.LogDebug("Reached end of topic {consumeResult.Topic}, partition {consumeResult.Partition}, offset {consumeResult.Offset}.");

                                        continue;
                                    }

                                    var EventId   = -1L;
                                    var MessageId = ea.Key;
                                    var TraceId   = MessageId;

                                    using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Received", TraceId))
                                    {
                                        #region 获取EventId & TraceId
                                        if (ea.Headers != null && ea.Headers.Count > 0)
                                        {
                                            try
                                            {
                                                long.TryParse(System.Text.Encoding.UTF8.GetString(ea.Headers.GetLastBytes("x-eventId")), out EventId);
                                            }
                                            catch
                                            { }

                                            try
                                            {
                                                TraceId = System.Text.Encoding.UTF8.GetString(ea.Headers.GetLastBytes("x-traceId"));
                                            }
                                            catch
                                            {
                                            }
                                        }
                                        #endregion

                                        tracer.SetComponent(_compomentName);
                                        tracer.SetTag("queueName", queueName);
                                        tracer.SetTag("x-messageId", MessageId);
                                        tracer.SetTag("x-eventId", EventId);
                                        tracer.SetTag("x-traceId", TraceId);

                                        Messages[j] = new EventResponse()
                                        {
                                            EventId    = EventId,
                                            MessageId  = MessageId,
                                            TraceId    = TraceId,
                                            Headers    = new Dictionary <string, object>(),
                                            Body       = default(TD),
                                            QueueName  = queueName,
                                            RouteKey   = routeKey,
                                            BodySource = ea.Value
                                        };

                                        try
                                        {
                                            #region 设置Body
                                            Messages[j].Body = JsonConvert.DeserializeObject <TD>(Messages[j].BodySource);
                                            #endregion

                                            #region 设置header
                                            foreach (var key in ea.Headers)
                                            {
                                                Messages[j].Headers.Add(key.Key, Encoding.UTF8.GetString(key.GetValueBytes()));
                                            }

                                            if (!Messages[j].Headers.ContainsKey("x-topic"))
                                            {
                                                Messages[j].Headers.Add("x-topic", routeKey);
                                            }
                                            if (!Messages[j].Headers.ContainsKey("x-messageId"))
                                            {
                                                Messages[j].Headers.Add("x-messageId", MessageId);
                                            }
                                            if (!Messages[j].Headers.ContainsKey("x-eventId"))
                                            {
                                                Messages[j].Headers.Add("x-eventId", EventId);
                                            }
                                            if (!Messages[j].Headers.ContainsKey("x-traceId"))
                                            {
                                                Messages[j].Headers.Add("x-traceId", TraceId);
                                            }
                                            #endregion

                                            _logger.LogDebug(Messages[j].BodySource);
                                        }
                                        catch (Exception ex)
                                        {
                                            _logger.LogError(ex, ex.Message);
                                        }
                                    }
                                }
                                #endregion

                                #region 批量处理消息

                                if (Messages != null && Messages.Any())
                                {
                                    using (var executeTracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Execute"))
                                    {
                                        executeTracer.SetComponent(_compomentName);
                                        executeTracer.SetTag("queueName", queueName);

                                        handlerSuccess = await _receiverPolicy.ExecuteAsync(async(handlerCancellationToken) =>
                                        {
                                            return(await eventAction.Handle(Messages.Select(a => (TD)a.Body).ToArray(), Messages.Select(a => (Dictionary <string, object>)a.Headers).ToArray(), handlerCancellationToken));
                                        }, cancellationToken);

                                        if (handlerSuccess)
                                        {
                                            #region 消息处理成功
                                            if (_subscribeAckHandler != null && Messages.Length > 0)
                                            {
                                                _subscribeAckHandler(Messages);
                                            }

                                            foreach (var group in eas.GroupBy(a => a.Partition))
                                            {
                                                consumer.StoreOffset(group.LastOrDefault());
                                            }

                                            #endregion
                                        }
                                        else
                                        {
                                            executeTracer.SetError();
                                        }
                                    }
                                }
                                #endregion
                            }
                            catch (Exception ex)
                            {
                                handlerException = ex;
                                _logger.LogError(ex, ex.Message);
                            }
                            finally
                            {
                                if (!handlerSuccess)
                                {
                                    //重新入队,默认:是
                                    var requeue = true;

                                    try
                                    {
                                        //执行回调,等待业务层的处理结果
                                        if (_subscribeNackHandler != null && Messages != null && Messages.Any())
                                        {
                                            requeue = await _subscribeNackHandler((Messages, handlerException));
                                        }
                                    }
                                    catch (Exception innterEx)
                                    {
                                        _logger.LogError(innterEx, innterEx.Message);
                                    }

                                    if (!requeue)
                                    {
                                        foreach (var group in eas.GroupBy(a => a.Partition))
                                        {
                                            consumer.StoreOffset(group.LastOrDefault());
                                        }
                                    }
                                    else
                                    {
                                        if (eas.Length > 0)
                                        {
                                            foreach (var group in eas.GroupBy(a => a.Partition))
                                            {
                                                consumer.Seek(group.FirstOrDefault().TopicPartitionOffset);

                                                Console.WriteLine($"kafk offset seek,topic={routeKey}                       partation={group.FirstOrDefault().TopicPartition.Partition}offset={group.FirstOrDefault().TopicPartitionOffset.Offset.Value}");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, ex.Message);

                    if (consumer != null)
                    {
                        consumer.Close();
                    }
                }
            });


            return(this);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// 订阅消息(同一类消息可以重复订阅)
        /// 作者:郭明
        /// 日期:2017年4月3日
        /// </summary>
        /// <typeparam name="TD"></typeparam>
        /// <typeparam name="TH"></typeparam>
        /// <param name="EventTypeName">消息类型名称</param>
        /// <returns></returns>
        public IEventBus RegisterBatch <TD, TH>(string QueueName, string EventTypeName = "", int BatchSize = 50, CancellationToken cancellationToken = default(CancellationToken))
            where TD : class
            where TH : IEventBatchHandler <TD>
        {
            var persistentConnection = _receiveLoadBlancer.Lease();
            var queueName            = string.IsNullOrEmpty(QueueName) ? typeof(TH).FullName : QueueName;
            var routeKey             = string.IsNullOrEmpty(EventTypeName) ? typeof(TD).FullName : EventTypeName;
            var eventAction          = _lifetimeScope.GetService(typeof(TH)) as IEventBatchHandler <TD>;

            if (eventAction == null)
            {
                eventAction = System.Activator.CreateInstance(typeof(TH)) as IEventBatchHandler <TD>;
            }

            for (int i = 0; i < _reveiverMaxDegreeOfParallelism; i++)
            {
                System.Threading.Tasks.Task.Run(async() =>
                {
                    try
                    {
                        var consumer = persistentConnection.GetConsumer();
                        consumer.Subscribe(routeKey);

                        while (true)
                        {
                            var handlerSuccess   = false;
                            var handlerException = default(Exception);
                            var eas      = consumer.ConsumeBatch(TimeSpan.FromSeconds(5), BatchSize, cancellationToken);
                            var Messages = new EventResponse[eas.Count()];

                            try
                            {
                                foreach (var ea in eas)
                                {
                                    // 消息队列空
                                    if (ea.IsPartitionEOF)
                                    {
                                        _logger.LogDebug("Reached end of topic {consumeResult.Topic}, partition {consumeResult.Partition}, offset {consumeResult.Offset}.");

                                        continue;
                                    }

                                    var EventId   = -1L;
                                    var MessageId = ea.Key;
                                    var TraceId   = MessageId;

                                    using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Received", TraceId))
                                    {
                                        #region 消息Header处理
                                        if (ea.Headers != null)
                                        {
                                            try
                                            {
                                                long.TryParse(System.Text.Encoding.UTF8.GetString(ea.Headers.GetLastBytes("x-eventId")), out EventId);
                                            }
                                            catch
                                            { }


                                            try
                                            {
                                                TraceId = System.Text.Encoding.UTF8.GetString(ea.Headers.GetLastBytes("x-traceId"));
                                            }
                                            catch
                                            {
                                            }
                                        }
                                        #endregion

                                        #region AMQP Received
                                        try
                                        {
                                            tracer.SetComponent(_compomentName);
                                            tracer.SetTag("queueName", queueName);
                                            tracer.SetTag("x-messageId", MessageId);
                                            tracer.SetTag("x-eventId", EventId);
                                            tracer.SetTag("x-traceId", TraceId);

                                            var eventResponse = new EventResponse()
                                            {
                                                EventId    = EventId,
                                                MessageId  = MessageId,
                                                TraceId    = TraceId,
                                                Headers    = new Dictionary <string, object>(),
                                                Body       = default(TD),
                                                QueueName  = queueName,
                                                RouteKey   = routeKey,
                                                BodySource = ea.Value
                                            };


                                            try
                                            {
                                                foreach (var key in ea.Headers)
                                                {
                                                    eventResponse.Headers.Add(key.Key, Encoding.UTF8.GetString(key.GetValueBytes()));
                                                }

                                                eventResponse.Body = JsonConvert.DeserializeObject <TD>(eventResponse.BodySource);
                                                _logger.LogInformation(eventResponse.BodySource);
                                            }
                                            catch (Exception ex)
                                            {
                                                _logger.LogError(ex, ex.Message);
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            tracer.SetError();
                                            _logger.LogError(ex.Message, ex);
                                        }
                                        #endregion
                                    }
                                }

                                if (Messages != null && Messages.Any())
                                {
                                    using (var executeTracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Execute"))
                                    {
                                        executeTracer.SetComponent(_compomentName);

                                        handlerSuccess = await _receiverPolicy.ExecuteAsync(async(handlerCancellationToken) =>
                                        {
                                            return(await eventAction.Handle(Messages.Select(a => (TD)a.Body).ToArray(), Messages.Select(a => (Dictionary <string, object>)a.Headers).ToArray(), handlerCancellationToken));
                                        }, cancellationToken);

                                        if (handlerSuccess)
                                        {
                                            #region 消息处理成功
                                            if (_subscribeAckHandler != null && Messages.Length > 0)
                                            {
                                                _subscribeAckHandler(Messages);
                                            }

                                            consumer.Commit();

                                            #endregion
                                        }
                                        else
                                        {
                                            executeTracer.SetError();
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError(ex, ex.Message);
                            }
                            finally
                            {
                                if (!handlerSuccess)
                                {
                                    //重新入队,默认:是
                                    var requeue = true;

                                    try
                                    {
                                        //执行回调,等待业务层的处理结果
                                        if (_subscribeNackHandler != null)
                                        {
                                            requeue = await _subscribeNackHandler((Messages, handlerException));
                                        }
                                    }
                                    catch (Exception innterEx)
                                    {
                                        _logger.LogError(innterEx, innterEx.Message);
                                    }

                                    if (!requeue)
                                    {
                                        consumer.Commit();
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, ex.Message);
                    }
                });
            }

            return(this);
        }