|
- using Confluent.Kafka;
- using DotNetty.Transport.Bootstrapping;
- using DotNetty.Transport.Channels;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Options;
- using NearCardAttendance.Common.helper;
- using NearCardAttendance.Model;
- using Newtonsoft.Json.Linq;
- using Newtonsoft.Json;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Text;
- using System.Threading.Tasks;
- using NearCardAttendance.Service.MessageQueue.Model;
-
- namespace NearCardAttendance.TcpServer
- {
- public class Server : BackgroundService
- {
- private readonly ILogger<Server> _logger;
- //private readonly IServiceProvider _serviceProvider;
- private readonly ServerBootstrap _serverBootstrap;
- // private IChannel _serverChannel = default!;
- private CancellationTokenSource _tokenSource = null!;
-
-
- private readonly ServiceConfig _configService;
- private readonly HttpHelper _httpHelper = default!;
- //private int _messageCount = 0;
-
-
- public Server(
- ILogger<Server> logger,
- ServerBootstrap serverBootstrap,
- IServiceProvider serviceProvider, HttpHelper httpHelper, IOptions<ServiceConfig> _optConfigService)
- {
- _logger = logger;
- //_serviceProvider = serviceProvider;
- _configService = _optConfigService.Value;
- _serverBootstrap = serverBootstrap;
- _httpHelper = httpHelper;
-
- }
- public override Task StartAsync(CancellationToken cancellationToken)
- {
- _logger.LogInformation("------StartAsync");
- _tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
- return base.StartAsync(cancellationToken);
- }
-
- public override Task StopAsync(CancellationToken cancellationToken)
- {
- _logger.LogInformation("------StopAsync");
- _tokenSource.Cancel(); //停止工作线程
- return base.StopAsync(cancellationToken);
- }
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
-
- _logger.LogInformation("DotNetty server starting...");
-
- //var address = new IPEndPoint(IPAddress.Any, 12345);
-
- //IChannel _serverChannel = await _serverBootstrap.BindAsync(address);
-
- string ipAddress = "0.0.0.0";
- int port = 16662;
- var endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
- IChannel _serverChannel = await _serverBootstrap.BindAsync(endPoint);
- // _serverChannel.GetAttribute(MessageIdAttribute.Key).Set("SomeRequestId");
-
- //_logger.LogInformation("DotNetty server started on {0}.", address);
- _logger.LogInformation("DotNetty server started on {0}.", endPoint);
-
- #region kafka
- var kafkaConsumer = CreateKafkaConsumer();
- kafkaConsumer.Subscribe("topics.storage.near_card_attendance");
- var tasks = new List<Task>();
- List<ConsumeResult<Ignore, string>> consumeBatchResult = new List<ConsumeResult<Ignore, string>>();
- try
- {
- while (!stoppingToken.IsCancellationRequested)
- {
- var consumeResult = kafkaConsumer.Consume(stoppingToken);
- if (consumeResult != null)
- {
- //_messageCount++;
- consumeBatchResult.Add(consumeResult);
-
- #if DEBUG
- if (consumeBatchResult.Count % 2 == 0)
- {
- if (!await ProcessBatchMessageAsync(consumeBatchResult, kafkaConsumer))
- { // 返回结果错误暂停5分钟
- await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
- }
- }
- //// 30条消息为一批
- #else
- if (consumeBatchResult.Count % 30 == 0)
- {
- if (!await ProcessBatchMessageAsync(consumeBatchResult, kafkaConsumer))
- { // 返回结果错误暂停5分钟
- await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
- }
- }
- #endif
-
-
- }
- }
- }
- catch (OperationCanceledException)
- {
- _logger.LogWarning("Worker exit");
- }
- catch (Exception ex)
- {
- _logger.LogError($"An error occurred: {ex.Message}");
- }
-
- #endregion
-
- // Wait until the service is stopped
- stoppingToken.WaitHandle.WaitOne();
-
- _logger.LogInformation("DotNetty server stopping...");
-
- // Close the server channel and release resources
- await _serverChannel.CloseAsync();
- _logger.LogInformation("DotNetty server stopped.");
- }
- private async Task<bool> ProcessBatchMessageAsync(List<ConsumeResult<Ignore, string>> consumeBatchResult, IConsumer<Ignore, string> kafkaConsumer)
- {
- try
- {
-
- var url = $"{_configService.XinHuaLeYuUrl}/user/electronicCardAttendance/receiveTbAttendanceRecordException";
- var list = new List<object>();
- //consumeBatchResult.ForEach(x => {
- // JObject msg = (JObject)JsonConvert.DeserializeObject(x.Message.Value)!;
- // list.Add(new
- // {
- // attendanceStatus = int.TryParse(msg["data"]!["attendanceStatus"]!.ToString(), out int status) ? status : 0,
- // attendanceTime = msg["data"]!["attendanceTime"]!.ToString(),
- // imei = msg["data"]!["imei"]!.ToString()
- // }) ;
- //});
-
- consumeBatchResult.ForEach(x => {
- EventData msg = JsonConvert.DeserializeObject<EventData>(x.Message.Value)!;
- JObject content = (JObject)JsonConvert.DeserializeObject(msg.Content)!;
- list.Add(new
- {
- attendanceStatus = int.TryParse(content!["attendanceStatus"]!.ToString(), out int status) ? status : 0,
- attendanceTime = content!["attendanceTime"]!.ToString(),
- imei = content!["imei"]!.ToString()
- });
- });
-
-
- var data = new
- {
- data = list
- };
- var res = await _httpHelper.HttpToPostAsync(url, data);
- if (!string.IsNullOrEmpty(res))
- {
- JObject resObj = (JObject)JsonConvert.DeserializeObject(res!)!;
- if ((bool)resObj["success"]!)
- {
- _logger.LogInformation($"{nameof(ProcessBatchMessageAsync)} 推送 {JsonConvert.SerializeObject(data)} 结果,{res}");
- consumeBatchResult.ForEach(x =>
- {
- kafkaConsumer.Commit(x);
- _logger.LogInformation($"完成消费:{JsonConvert.SerializeObject(x.Message.Value)}");
- });
- consumeBatchResult.Clear();
- return true;
- }
- }
-
- }
- catch (Exception ex)
- {
- _logger.LogError($"处理消息出错 \n{ex.Message}\n{ex.StackTrace}");
-
- }
- return false;
-
- }
-
- private IConsumer<Ignore, string> CreateKafkaConsumer()
- {
-
- var consumerConfig = new ConsumerConfig
- {
- GroupId = "near_card_attendance",
- BootstrapServers = _configService.KafkaServerAddress,
- AutoOffsetReset = AutoOffsetReset.Earliest,
- EnableAutoCommit = false, // 关闭自动提交偏移量
- //CancellationDelayMaxMs = 1//set CancellationDelayMaxMs
- };
-
- return new ConsumerBuilder<Ignore, string>(consumerConfig)
- .SetErrorHandler((_, e) =>
- {
-
- //Console.WriteLine($"消费者创建出错,代码:{e.Code} |原因: {e.Reason}");
- _logger.LogInformation($"消费者创建出错,代码:{e.Code} |原因: {e.Reason}");
- })
- .SetPartitionsAssignedHandler((c, partitions) =>
- {
- //// 在这里手动指定要消费的分区
- //var partitionsToConsume = new List<TopicPartitionOffset>
- //{
- // new TopicPartitionOffset("topics.storage.near_card_attendance", partitionIndex, Offset.Unset)
- //};
-
- ////c.Assign(partitionsToConsume);
- //Console.WriteLine($"Assigned partitions: {string.Join(", ", partitionsToConsume)}");
- //return partitionsToConsume;
- })
- .SetPartitionsRevokedHandler((c, partitions) =>
- {
-
- })
- .Build();
- }
-
-
- }
- }
|