Пример #1
0
        public async Task <Response <ServiceHostAndPort> > Lease(DownstreamContext context)
        {
            var value = context.HttpContext.Request.Cookies[_key];

            if (!string.IsNullOrEmpty(value) && _stored.ContainsKey(value))
            {
                var cached = _stored[value];

                var updated = new StickySession(cached.HostAndPort, DateTime.UtcNow.AddMilliseconds(_expiryInMs));

                _stored[value] = updated;

                return(new OkResponse <ServiceHostAndPort>(updated.HostAndPort));
            }

            var next = await _loadBalancer.Lease(context);

            if (next.IsError)
            {
                return(new ErrorResponse <ServiceHostAndPort>(next.Errors));
            }

            if (!string.IsNullOrEmpty(value) && !_stored.ContainsKey(value))
            {
                _stored[value] = new StickySession(next.Data, DateTime.UtcNow.AddMilliseconds(_expiryInMs));
            }

            return(new OkResponse <ServiceHostAndPort>(next.Data));
        }
Пример #2
0
        private void Enqueue(List <EventMessage> Events, CancellationToken cancellationToken)
        {
            var persistentConnection = _senderLoadBlancer.Lease();

            try
            {
                var channel = persistentConnection.GetProducer();
                var groups  = Events.GroupBy(a => a.RouteKey).Select(a => a.Key);

                foreach (var topic in groups)
                {
                    var messages  = new List <Message <string, string> >();
                    var curEvents = Events.Where(a => a.RouteKey == topic).ToArray();
                    for (var eventIndex = 0; eventIndex < curEvents.Count(); eventIndex++)
                    {
                        using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Publish"))
                        {
                            tracer.SetComponent(_compomentName);
                            tracer.SetTag("x-eventId", curEvents[eventIndex].EventId);
                            tracer.SetTag("x-messageId", curEvents[eventIndex].MessageId);
                            tracer.SetTag("x-traceId", curEvents[eventIndex].TraceId);
                            _logger.LogInformation(curEvents[eventIndex].Body);

                            var message = new Message <string, string>();
                            message.Key       = curEvents[eventIndex].MessageId;
                            message.Timestamp = curEvents[eventIndex].Timestamp;
                            message.Value     = curEvents[eventIndex].Body;
                            message.Headers   = new Headers();

                            foreach (var key in curEvents[eventIndex].Headers.Keys)
                            {
                                message.Headers.Add(new Header(key, UTF8Encoding.UTF8.GetBytes(curEvents[eventIndex].Headers[key] as string)));
                            }


                            messages.Add(message);
                        }
                    }

                    channel.ProduceBatch(topic, messages, TimeSpan.FromMilliseconds(_senderConfirmTimeoutMillseconds), TimeSpan.FromMilliseconds(_senderConfirmFlushTimeoutMillseconds), cancellationToken);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                throw ex;
            }
        }
Пример #3
0
        public async Task <Response <ServiceHostAndPort> > Lease(DownstreamContext context)
        {
            var key = context.HttpContext.Request.Cookies[_key];

            lock (_lock)
            {
                if (!string.IsNullOrEmpty(key) && _stored.ContainsKey(key))
                {
                    var cached = _stored[key];

                    var updated = new StickySession(cached.HostAndPort, DateTime.UtcNow.AddMilliseconds(_keyExpiryInMs), key);

                    _stored[key] = updated;

                    _bus.Publish(updated, _keyExpiryInMs);

                    return(new OkResponse <ServiceHostAndPort>(updated.HostAndPort));
                }
            }

            var next = await _loadBalancer.Lease(context);

            if (next.IsError)
            {
                return(new ErrorResponse <ServiceHostAndPort>(next.Errors));
            }

            lock (_lock)
            {
                if (!string.IsNullOrEmpty(key) && !_stored.ContainsKey(key))
                {
                    var ss = new StickySession(next.Data, DateTime.UtcNow.AddMilliseconds(_keyExpiryInMs), key);
                    _stored[key] = ss;
                    _bus.Publish(ss, _keyExpiryInMs);
                }
            }

            return(new OkResponse <ServiceHostAndPort>(next.Data));
        }
Пример #4
0
        /// <summary>
        /// 订阅消息(同一类消息可以重复订阅)
        /// 作者:郭明
        /// 日期:2017年4月3日
        /// </summary>
        /// <typeparam name="TD"></typeparam>
        /// <typeparam name="TH"></typeparam>
        /// <param name="QueueName">消息类型名称</param>
        /// <param name="EventTypeName">消息类型名称</param>
        /// <returns></returns>
        public IEventBus Register <TD, TH>(string QueueName, string EventTypeName = "", CancellationToken cancellationToken = default(CancellationToken))
            where TD : class
            where TH : IEventHandler <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 IEventHandler <TD>;

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


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

                try
                {
                    consumer = persistentConnection.GetConsumer();
                    consumer.Subscribe(routeKey);
                    while (!cancellationToken.IsCancellationRequested)
                    {
                        try
                        {
                            var ea = consumer.Consume(cancellationToken);

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

                                continue;
                            }
                            else
                            {
                                _logger.LogInformation($"Consumed message '{ea.Value}' at: '{ea.TopicPartitionOffset}'.");
                            }

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

                            using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Received", TraceId))
                            {
                                #region 获取EventId 和 TracerId
                                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

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

                                try
                                {
                                    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
                                    };


                                    #region 格式化消息
                                    try
                                    {
                                        #region 设置body
                                        eventResponse.Body = JsonConvert.DeserializeObject <TD>(eventResponse.BodySource);
                                        #endregion

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

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

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

                                    #region 处理消息
                                    using (var tracerExecuteAsync = new Hummingbird.Extensions.Tracing.Tracer("AMQP Execute"))
                                    {
                                        var handlerSuccess   = false;
                                        var handlerException = default(Exception);

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

                                        try
                                        {
                                            handlerSuccess = await _receiverPolicy.ExecuteAsync(async(handlerCancellationToken) =>
                                            {
                                                return(await eventAction.Handle(eventResponse.Body, (Dictionary <string, object>)eventResponse.Headers, handlerCancellationToken));
                                            }, CancellationToken.None);

                                            if (handlerSuccess)
                                            {
                                                if (_subscribeAckHandler != null)
                                                {
                                                    _subscribeAckHandler(new EventResponse[] { eventResponse });
                                                }

                                                consumer.StoreOffset(ea);
                                                _logger.LogInformation($"kafk offset store,topic={routeKey} partation={ea.TopicPartition.Partition}offset={ea.TopicPartitionOffset.Offset.Value}");


                                                //   consumer.Commit(ea);
                                                //   Console.WriteLine($"kafk offset commit,topic={routeKey} partation={ea.TopicPartition.Partition}offset={ea.TopicPartitionOffset.Offset.Value}");
                                            }
                                            else
                                            {
                                                tracerExecuteAsync.SetError();
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            tracerExecuteAsync.SetError();
                                            handlerException = ex;
                                            _logger.LogError(ex, ex.Message);
                                        }
                                        finally
                                        {
                                            if (!handlerSuccess)
                                            {
                                                //重新入队,默认:是
                                                var requeue = true;

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

                                                if (!requeue)
                                                {
                                                    consumer.StoreOffset(ea);
                                                    _logger.LogInformation($"kafk offset store,topic={routeKey} partation={ea.TopicPartition.Partition}offset={ea.TopicPartitionOffset.Offset.Value}");


                                                    //   consumer.Commit(ea);
                                                    //    Console.WriteLine($"kafk offset commit,topic={routeKey} partation={ea.TopicPartition.Partition}offset={ea.TopicPartitionOffset.Offset.Value}");
                                                }
                                                else
                                                {
                                                    consumer.Seek(ea.TopicPartitionOffset); //重新入队重试

                                                    _logger.LogInformation($"kafk offset seek,topic={routeKey} partation={ea.TopicPartition.Partition}offset={ea.TopicPartitionOffset.Offset.Value}");
                                                }
                                            }
                                        }
                                    }
                                    #endregion
                                }
                                catch (Exception ex)
                                {
                                    tracer.SetError();
                                    _logger.LogError(ex.Message, ex);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, ex.Message);

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

            return(this);
        }
Пример #5
0
        /// <summary>
        /// 订阅消息(同一类消息可以重复订阅)
        /// 作者:郭明
        /// 日期:2017年4月3日
        /// </summary>
        /// <typeparam name="TD"></typeparam>
        /// <typeparam name="TH"></typeparam>
        /// <param name="QueueName">消息类型名称</param>
        /// <param name="EventTypeName">消息类型名称</param>
        /// <returns></returns>
        public IEventBus Register <TD, TH>(string QueueName, string EventTypeName = "", CancellationToken cancellationToken = default(CancellationToken))
            where TD : class
            where TH : IEventHandler <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 IEventHandler <TD>;

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

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

            for (int i = 0; i < _reveiverMaxDegreeOfParallelism; i++)
            {
                System.Threading.Tasks.Task.Run(() =>
                {
                    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, _preFetch, false);
                        //在队列上定义一个消费者a
                        EventingBasicConsumer consumer = new EventingBasicConsumer(_channel);

                        consumer.Received += async(ch, ea) =>
                        {
                            using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Received"))
                            {
                                try
                                {
                                    #region Ensure IsConnected
                                    if (!persistentConnection.IsConnected)
                                    {
                                        persistentConnection.TryConnect();
                                    }
                                    #endregion

                                    var EventId   = -1L;
                                    var MessageId = string.IsNullOrEmpty(ea.BasicProperties.MessageId) ? Guid.NewGuid().ToString("N") : ea.BasicProperties.MessageId;
                                    var TraceId   = MessageId;

                                    #region 获取 eventId
                                    if (ea.BasicProperties.Headers != null && ea.BasicProperties.Headers.ContainsKey("x-eventId"))
                                    {
                                        try
                                        {
                                            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 获取 eventId

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

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

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

                                    try
                                    {
                                        #region 设置body
                                        eventResponse.Body = JsonConvert.DeserializeObject <TD>(eventResponse.BodySource);
                                        #endregion

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

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

                                        _logger.LogInformation(eventResponse.BodySource);
                                    }
                                    catch (Exception ex)
                                    {
                                        _logger.LogError(ex, ex.Message);
                                    }

                                    #region AMQP ExecuteAsync
                                    using (var tracerExecuteAsync = new Hummingbird.Extensions.Tracing.Tracer("AMQP Execute"))
                                    {
                                        var handlerSuccess   = false;
                                        var handlerException = default(Exception);

                                        try
                                        {
                                            handlerSuccess = await _receiverPolicy.ExecuteAsync(async(handlerCancellationToken) =>
                                            {
                                                return(await eventAction.Handle(eventResponse.Body, (Dictionary <string, object>)eventResponse.Headers, handlerCancellationToken));
                                            }, cancellationToken);

                                            if (handlerSuccess)
                                            {
                                                if (_subscribeAckHandler != null)
                                                {
                                                    _subscribeAckHandler(new EventResponse[] { eventResponse });
                                                }

                                                //确认消息
                                                _channel.BasicAck(ea.DeliveryTag, false);
                                            }
                                            else
                                            {
                                                tracerExecuteAsync.SetError();
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            _logger.LogError(ex, ex.Message);
                                            tracerExecuteAsync.SetError();
                                            handlerException = ex;
                                        }
                                        finally
                                        {
                                            if (!handlerSuccess)
                                            {
                                                //重新入队,默认:是
                                                var requeue = true;

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

                                                //确认消息
                                                _channel.BasicReject(ea.DeliveryTag, requeue);
                                            }
                                        }
                                    }
                                    #endregion
                                }
                                catch (Exception ex)
                                {
                                    tracer.SetError();
                                    _logger.LogError(ex.Message, ex);
                                }
                            }
                        };

                        consumer.Unregistered += (ch, ea) =>
                        {
                            _logger.LogDebug($"MQ:{queueName} Consumer_Unregistered");
                        };

                        consumer.Registered += (ch, ea) =>
                        {
                            _logger.LogDebug($"MQ:{queueName} Consumer_Registered");
                        };

                        consumer.Shutdown += (ch, ea) =>
                        {
                            _logger.LogDebug($"MQ:{queueName} Consumer_Shutdown.{ea.ReplyText}");
                        };

                        consumer.ConsumerCancelled += (object sender, ConsumerEventArgs e) =>
                        {
                            _logger.LogDebug($"MQ:{queueName} ConsumerCancelled");
                        };

                        //消费队列,并设置应答模式为程序主动应答
                        _channel.BasicConsume(queueName, false, consumer);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, ex.Message);
                    }
                });
            }

            return(this);
        }
Пример #6
0
        private async Task <bool> Enqueue(List <EventMessage> Events, bool confirm, CancellationToken cancellationToken = default(CancellationToken))
        {
            var persistentConnection = _senderLoadBlancer.Lease();

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

                var channel = persistentConnection.GetProducer();

                // 提交走批量通道
                var batchPublish = channel.CreateBasicPublishBatch();

                for (var eventIndex = 0; eventIndex < Events.Count; eventIndex++)
                {
                    await _senderRetryPolicy.ExecuteAsync((ct) =>
                    {
                        var MessageId = Events[eventIndex].MessageId;
                        var json      = Events[eventIndex].Body;
                        var routeKey  = Events[eventIndex].RouteKey;
                        byte[] bytes  = Encoding.UTF8.GetBytes(json);
                        //设置消息持久化
                        IBasicProperties properties     = channel.CreateBasicProperties();
                        properties.DeliveryMode         = 2;
                        properties.MessageId            = MessageId;
                        properties.Headers              = new Dictionary <string, Object>();
                        properties.Headers["x-eventId"] = Events[eventIndex].EventId;
                        properties.Headers["x-traceId"] = Events[eventIndex].TraceId;
                        using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("AMQP Publish"))
                        {
                            tracer.SetComponent(_compomentName);
                            tracer.SetTag("x-messageId", MessageId);
                            tracer.SetTag("x-eventId", Events[eventIndex].EventId);
                            tracer.SetTag("x-traceId", Events[eventIndex].TraceId);
                            _logger.LogInformation(json);

                            foreach (var key in Events[eventIndex].Headers.Keys)
                            {
                                if (!properties.Headers.ContainsKey(key))
                                {
                                    properties.Headers.Add(key, Events[eventIndex].Headers[key]);
                                }
                            }

                            if (Events[eventIndex].Headers.ContainsKey("x-first-death-queue"))
                            {
                                //延时队列或者直接写死信的情况
                                var newQueue = Events[eventIndex].Headers["x-first-death-queue"].ToString();

                                //创建一个队列
                                channel.QueueDeclare(
                                    queue: newQueue,
                                    durable: true,
                                    exclusive: false,
                                    autoDelete: false,
                                    arguments: Events[eventIndex].Headers);

                                batchPublish.Add(
                                    exchange: "",
                                    mandatory: true,
                                    routingKey: newQueue,
                                    properties: properties,
                                    body: bytes);
                            }
                            else
                            {
                                //发送到正常队列
                                batchPublish.Add(
                                    exchange: _exchange,
                                    mandatory: true,
                                    routingKey: routeKey,
                                    properties: properties,
                                    body: bytes);
                            }
                        }

                        return(Task.FromResult(true));
                    }, cancellationToken);
                }

                //批量提交
                batchPublish.Publish();

                if (confirm)
                {
                    return(channel.WaitForConfirms(TimeSpan.FromMilliseconds(_senderConfirmTimeoutMillseconds)));
                }
                else
                {
                    return(true);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                throw ex;
            }
        }