ソースを参照

正式环境配置

develop
H Vs 8ヶ月前
コミット
e29ab30091
3個のファイルの変更12行の追加288行の削除
  1. +4
    -0
      NearCardAttendance.TcpServer/NearCardAttendance.TcpServer.csproj
  2. +0
    -288
      NearCardAttendance.TcpServer/Worker.cs
  3. +8
    -0
      NearCardAttendance.TcpServer/appsettings.production.json

+ 4
- 0
NearCardAttendance.TcpServer/NearCardAttendance.TcpServer.csproj ファイルの表示

@@ -11,10 +11,14 @@
<ItemGroup>
<None Remove="appsettings.debug.json" />
<None Remove="appsettings.json" />
<None Remove="appsettings.production.json" />
<None Remove="appsettings.test.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.production.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.test.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>


+ 0
- 288
NearCardAttendance.TcpServer/Worker.cs ファイルの表示

@@ -1,288 +0,0 @@
using Confluent.Kafka;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NearCardAttendance.Model;
using Newtonsoft.Json;
using Serilog.Context;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NearCardAttendance.Common.helper;
using Newtonsoft.Json.Linq;
using NearCardAttendance.Service.MessageQueue.Model;


namespace NearCardAttendance.TcpServer
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly ServiceConfig _configService;
private readonly HttpHelper _httpHelper = default!;
private int _messageCount = 0;

public Worker(ILogger<Worker> logger, IOptions<ServiceConfig> _optConfigService,HttpHelper httpHelper)
{
_logger = logger;
_configService = _optConfigService.Value;
_httpHelper = httpHelper;
}
/**
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var kafkaConsumer = CreateKafkaConsumer();
kafkaConsumer.Subscribe("topics.storage.near_card_attendance");

// process messages every 50 messages or every minute
// 每隔1分钟或没50条消息就批量处理一次
var tasks = new List<Task>();

#region 每分钟触发一次
var messageCounter = 0; // 消息计数器
var timer = new System.Timers.Timer(TimeSpan.FromMinutes(1).TotalMilliseconds); // 定时器,每分钟触发一次
timer.AutoReset = true;

// 定时器事件处理程序,用于定时处理消息
timer.Elapsed += async (sender, e) =>
{
// 如果计数器大于 0,则处理消息
if (messageCounter > 0)
{
await ProcessMessagesAsync(tasks);
messageCounter = 0; // 处理完成后重置计数器
}
};

timer.Start(); // 启动定时器
#endregion

try
{
while (!stoppingToken.IsCancellationRequested)
{
var consumeResult = kafkaConsumer.Consume(stoppingToken);
if (consumeResult != null)
{
//tasks.Add(ProcessMessageAsync(consumeResult, kafkaConsumer));
// 处理消息
tasks.Add(ProcessMessageAsync(consumeResult, kafkaConsumer));
messageCounter++; // 增加消息计数器

// 如果消息计数达到 30 条,则处理消息并重置计数器
if (messageCounter >= 30)
{
await ProcessMessagesAsync(tasks);
messageCounter = 0; // 处理完成后重置计数器
}
}
}
}
catch (OperationCanceledException)
{
_logger.LogWarning("Worker exit");
}
catch (Exception ex)
{
_logger.LogError($"An error occurred: {ex.Message}");
}

await Task.WhenAll(tasks);
}

// 异步处理消息的方法
private async Task ProcessMessagesAsync(List<Task> tasks)
{
await Task.WhenAll(tasks); // 等待所有任务完成
tasks.Clear(); // 清空任务列表
}

private async Task ProcessMessageAsync(ConsumeResult<Ignore, string> consumeResult, IConsumer<Ignore, string> kafkaConsumer)
{
// 处理消息的逻辑
if (consumeResult != null)
{

try
{
var url = _configService.XinHuaLeYuUrl;
var data = new { };
var res = await _httpHelper.HttpToPostAsync(url, data);

}
catch (Exception ex)
{
//kafkaConsumer.Commit(consumeResult);
_logger.LogError($"消费出错:{consumeResult.Message.Value},\n{ex.Message}\n{ex.StackTrace}");
}
}
}
*/

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
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);
//// 30条消息为一批
if (_messageCount % 30 == 0)
{
if (!await ProcessBatchMessageAsync(consumeBatchResult, kafkaConsumer))
{ // 返回结果错误暂停5分钟
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}

}
}
}
catch (OperationCanceledException)
{
_logger.LogWarning("Worker exit");
}
catch (Exception ex)
{
_logger.LogError($"An error occurred: {ex.Message}");
}
}
private async Task<bool> ProcessMessageAsync(ConsumeResult<Ignore, string> consumeResult, IConsumer<Ignore, string> kafkaConsumer)
{
try
{
var url = _configService.XinHuaLeYuUrl;
var data = new { };
var res = await _httpHelper.HttpToPostAsync(url, data);
if (!string.IsNullOrEmpty(res))
{
JObject resObj = (JObject)JsonConvert.DeserializeObject(res!)!;
if ((bool)resObj["success"]!)
{
kafkaConsumer.Commit(consumeResult);
return true;
}
}
}
catch (Exception ex)
{
//kafkaConsumer.Commit(consumeResult);
_logger.LogError($"消费出错:{consumeResult.Message.Value},\n{ex.Message}\n{ex.StackTrace}");
}
return false;

}

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"]!)
{
consumeBatchResult.ForEach(x =>
{
kafkaConsumer.Commit(x);
});
return true;
}
}

}
catch (Exception ex)
{
_logger.LogError($"处理消息出错 \n{ex.Message}\n{ex.StackTrace}");

}
return false;

}


/// <summary>
/// 创建消费者
/// </summary>
/// <returns></returns>
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();
}
}
}

+ 8
- 0
NearCardAttendance.TcpServer/appsettings.production.json ファイルの表示

@@ -0,0 +1,8 @@
{
"AllowedHosts": "*",
"ServiceConfig": {
"XinHuaLeYuUrl": "https://midplat.xinhualeyu.com/dev-api",
"TelpoDataUrl": "https://ai.ssjlai.com/data",
"KafkaServerAddress": "172.19.42.40:9092,172.19.42.41:9092,172.19.42.48:9092"
}
}

読み込み中…
キャンセル
保存