Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

153 rindas
6.2KB

  1. using HealthMonitor.Common;
  2. using HealthMonitor.Model.Config;
  3. using Microsoft.EntityFrameworkCore.Diagnostics;
  4. using Microsoft.Extensions.Logging;
  5. using Microsoft.Extensions.Options;
  6. using Newtonsoft.Json;
  7. using Confluent.Kafka;
  8. using System;
  9. using System.Collections.Concurrent;
  10. using System.Collections.Generic;
  11. using System.DirectoryServices.Protocols;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Threading.Tasks;
  15. namespace HealthMonitor.Service.MessageQueue.Kafka
  16. {
  17. public class KafkaService : IKafkaService
  18. {
  19. private readonly ILogger<KafkaService> _logger;
  20. private readonly ServiceConfig _configService;
  21. public KafkaService(IOptions<ServiceConfig> _optConfigService, ILogger<KafkaService> logger)
  22. {
  23. _configService = _optConfigService.Value;
  24. _logger = logger;
  25. }
  26. public async Task PublishAsync<T>(string topicName, T message) where T : class
  27. {
  28. try
  29. {
  30. Type messageType = typeof(T);
  31. var config = new ProducerConfig
  32. {
  33. BootstrapServers = _configService.KafkaServerAddress,
  34. EnableIdempotence = true,
  35. Acks = Acks.All,
  36. MessageSendMaxRetries = 3
  37. };
  38. using var producer = new ProducerBuilder<string, string>(config).Build();
  39. await producer.ProduceAsync(topicName, new Message<string, string>
  40. {
  41. Key = Guid.NewGuid().ToString(),
  42. Value = JsonConvert.SerializeObject(message)
  43. });
  44. }
  45. catch (ProduceException<Null, string> ex)
  46. {
  47. _logger.LogError($"推送到kafka失败,topic: {topicName},\n message:{JsonConvert.SerializeObject(message)}: \n{ex.Error.Reason}");
  48. }
  49. }
  50. public async Task PublishAsync<T>(string topicName, int dataType, T message) where T : class
  51. {
  52. try
  53. {
  54. Type messageType = typeof(T);
  55. var config = new ProducerConfig
  56. {
  57. BootstrapServers = _configService.KafkaServerAddress,
  58. EnableIdempotence = true,
  59. Acks = Acks.All,
  60. MessageSendMaxRetries = 3
  61. };
  62. Headers headers = new()
  63. {
  64. { "DataType", BitConverter.GetBytes(dataType) }
  65. };
  66. using var producer = new ProducerBuilder<string, string>(config).Build();
  67. await producer.ProduceAsync(topicName, new Message<string, string>
  68. {
  69. Headers= headers,
  70. Key = Guid.NewGuid().ToString(),
  71. Value = JsonConvert.SerializeObject(message)
  72. });
  73. }
  74. catch (ProduceException<Null, string> ex)
  75. {
  76. _logger.LogError($"推送到kafka失败,topic: {topicName},\n message:{JsonConvert.SerializeObject(message)}: \n{ex.Error.Reason}");
  77. }
  78. }
  79. public async Task SubscribeAsync<T>(IEnumerable<string> topics, Action<T> messageFunc, CancellationToken cancellationToken = default) where T : class
  80. {
  81. var config = new ConsumerConfig
  82. {
  83. BootstrapServers = _configService.KafkaServerAddress,
  84. GroupId = "Consumer",
  85. EnableAutoCommit = false, // 禁止AutoCommit
  86. Acks = Acks.Leader, // 假设只需要Leader响应即可
  87. AutoOffsetReset = AutoOffsetReset.Earliest // 从最早的开始消费起
  88. };
  89. using (var consumer = new ConsumerBuilder<Ignore, string>(config).Build())
  90. {
  91. consumer.Subscribe(topics);
  92. try
  93. {
  94. while (true)
  95. {
  96. try
  97. {
  98. var consumeResult = consumer.Consume(cancellationToken);
  99. Console.WriteLine($"Consumed message '{consumeResult.Message?.Value}' at: '{consumeResult?.TopicPartitionOffset}'.");
  100. if (consumeResult!.IsPartitionEOF)
  101. {
  102. Console.WriteLine($" - {DateTime.Now:yyyy-MM-dd HH:mm:ss} 已经到底了:{consumeResult.Topic}, partition {consumeResult.Partition}, offset {consumeResult.Offset}.");
  103. continue;
  104. }
  105. T? messageResult = null;
  106. try
  107. {
  108. messageResult = JsonConvert.DeserializeObject<T>(consumeResult.Message!.Value)!;
  109. }
  110. catch (Exception ex)
  111. {
  112. var errorMessage = $" - {DateTime.Now:yyyy-MM-dd HH:mm:ss}【Exception 消息反序列化失败,Value:{consumeResult.Message!.Value}】 :{ex.StackTrace?.ToString()}";
  113. Console.WriteLine(errorMessage);
  114. messageResult = null;
  115. }
  116. if (messageResult != null/* && consumeResult.Offset % commitPeriod == 0*/)
  117. {
  118. messageFunc(messageResult);
  119. try
  120. {
  121. consumer.Commit(consumeResult);
  122. }
  123. catch (KafkaException e)
  124. {
  125. Console.WriteLine(e.Message);
  126. }
  127. }
  128. }
  129. catch (ConsumeException e)
  130. {
  131. Console.WriteLine($"Consume error: {e.Error.Reason}");
  132. }
  133. }
  134. }
  135. catch (OperationCanceledException)
  136. {
  137. Console.WriteLine("Closing consumer.");
  138. consumer.Close();
  139. }
  140. }
  141. await Task.CompletedTask;
  142. }
  143. }
  144. }