public async Task <HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer", IDictionary <string, string> dictionary = null, CancellationToken cancellationToken = default(CancellationToken)) { uri = await ResolveUri(uri); var origin = GetOriginFromUri(uri); return(await HttpInvoker(origin, async (context, ctx) => { using (var tracer = new Hummingbird.Extensions.Tracing.Tracer("HTTP DELETE")) { tracer.SetComponent(_compomentName); tracer.SetTag("http.url", uri); tracer.SetTag("http.method", "DELETE"); var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri); SetAuthorizationHeader(requestMessage); if (authorizationToken != null) { requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); } if (dictionary != null) { foreach (var key in dictionary.Keys) { requestMessage.Headers.Add(key, dictionary[key]); } } var response = await _client.SendAsync(requestMessage, ctx); #region LOG:记录返回 var responseContent = await response.Content.ReadAsStringAsync(); tracer.SetTag("http.status_code", (int)response.StatusCode); if (dictionary != null && dictionary.ContainsKey("x-masking") && (dictionary["x-masking"] == "all" || dictionary["x-masking"] == "response")) { //日志脱敏不记录 } else { _logger.LogInformation("Http Request Executed :{responseContent}", responseContent); } #endregion if (response.StatusCode == HttpStatusCode.InternalServerError) { throw new HttpRequestException(response.ReasonPhrase); } return response; } }, cancellationToken)); }
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; } }
public async Task Test() { using (Hummingbird.Extensions.Tracing.Tracer tracer = new Hummingbird.Extensions.Tracing.Tracer("Test")) { tracer.SetTag("tag1", "value1"); tracer.SetError(); tracer.Log("key1", "value1"); } }
private async Task <HttpResponseMessage> DoPostPutAsync <T>(HttpMethod method, string uri, T item, string authorizationToken = null, AuthorizationTypeEnum authorizationType = AuthorizationTypeEnum.Bearer, IDictionary <string, string> dictionary = null, CancellationToken cancellationToken = default(CancellationToken)) { if (method != HttpMethod.Post && method != HttpMethod.Put) { throw new ArgumentException("Value must be either post or put.", nameof(method)); } uri = await ResolveUri(uri); var origin = GetOriginFromUri(uri); return(await HttpInvokerAsync(origin, async (context, ctx) => { using (var tracer = new Hummingbird.Extensions.Tracing.Tracer($"HTTP {method.Method.ToUpper()}")) { tracer.SetComponent(_compomentName); tracer.SetTag("http.url", uri); tracer.SetTag("http.method", method.Method.ToUpper()); var requestMessage = new HttpRequestMessage(method, uri); var requestContent = JsonConvert.SerializeObject(item); #region LOG:记录请求 if (dictionary != null && dictionary.ContainsKey("x-masking") && (dictionary["x-masking"] == "all" || dictionary["x-masking"] == "request")) { //日志脱敏 } else { _logger.LogInformation("Http Request Executing:{requestContent}", requestContent); } #endregion SetAuthorizationHeader(requestMessage); requestMessage.Content = new StringContent(requestContent, System.Text.Encoding.UTF8, "application/json"); if (authorizationToken != null) { requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken); } if (dictionary != null) { foreach (var key in dictionary.Keys) { requestMessage.Headers.Add(key, dictionary[key]); } } var response = await _client.SendAsync(requestMessage, ctx); var responseContent = await response.Content.ReadAsStringAsync(); #region LOG:记录返回 tracer.SetTag("http.status_code", (int)response.StatusCode); if (dictionary != null && dictionary.ContainsKey("x-masking") && (dictionary["x-masking"] == "all" || dictionary["x-masking"] == "response")) { //日志脱敏不记录 } else { _logger.LogInformation("Http Request Executed:{responseContent}", responseContent); } #endregion if (response.StatusCode == HttpStatusCode.InternalServerError) { throw new HttpRequestException(response.ReasonPhrase); } return response; } }, cancellationToken)); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
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; } }
/// <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); }