diff --git a/AutoNotificatPhone.csproj b/AutoNotificatPhone.csproj index 6ee7017..2be35e0 100644 --- a/AutoNotificatPhone.csproj +++ b/AutoNotificatPhone.csproj @@ -9,6 +9,7 @@ + diff --git a/CSRedisCacheHelper.cs b/CSRedisCacheHelper.cs index affbb3e..51fddc7 100644 --- a/CSRedisCacheHelper.cs +++ b/CSRedisCacheHelper.cs @@ -17,14 +17,14 @@ namespace Common public static CSRedisClient? redis1; private const string ip = "127.0.0.1"; - private const string port = "6379"; + private const string port = "10079";//10079 static CSRedisCacheHelper() { var redisHostStr = string.Format("{0}:{1}", ip, port); if (!string.IsNullOrEmpty(redisHostStr)) { - redis = new CSRedisClient(redisHostStr + ",password=,defaultDatabase=0"); - redis1 = new CSRedisClient(redisHostStr + ",password=,defaultDatabase=1"); + redis = new CSRedisClient(redisHostStr + ",password=blw@redis-ser@123,defaultDatabase=0"); + redis1 = new CSRedisClient(redisHostStr + ",password=blw@redis-ser@123,defaultDatabase=1"); var DingYueMsg = ("CallServer", new Action(async (args) => { string body = args.Body; diff --git a/Models/TimerClass.cs b/Models/TimerClass.cs index bfd8124..449b838 100644 --- a/Models/TimerClass.cs +++ b/Models/TimerClass.cs @@ -3,6 +3,8 @@ using Common; using System.Threading; using NLog; using System.Diagnostics; +using Npgsql; +using Microsoft.Extensions.Configuration; namespace AutoNotificatPhone.Models { @@ -17,6 +19,12 @@ namespace AutoNotificatPhone.Models private Dictionary _executedTasks = []; // 消息控制器实例 private readonly CallAndMsgController _callAndMsgController = new(); + private readonly IConfiguration _configuration; + + public TimerClass(IConfiguration configuration) + { + _configuration = configuration; + } /// /// 后台服务主执行方法 @@ -48,6 +56,7 @@ namespace AutoNotificatPhone.Models await CheckRcuOnlineAsync(); await CheckTotalSendPackageAsync(); await CheckTotalRecvPackageAsync(); + await CheckKafkaHeartbeatAsync(); } catch (TaskCanceledException) { @@ -262,7 +271,7 @@ namespace AutoNotificatPhone.Models //logger.Error($"RCU服务器的CPU使用率-AVG:{cpuAvg},MAX:{cpuMax}"); // 检查是否超过阈值 - if (CheckThreshold(cpuAvgValues, 70, 6))//(CheckThreshold(cpuMaxValues, 90, 6) || CheckThreshold(cpuAvgValues, 85, 6)) + if (CheckThreshold(cpuAvgValues, 80, 6))//(CheckThreshold(cpuMaxValues, 90, 6) || CheckThreshold(cpuAvgValues, 85, 6)) { // 触发CPU警报 ExecuteCpuAlert(cpuMaxValues, ParseCpuValues(CSRedisCacheHelper.redis1.Get("UDPPackage_CPUMin")), cpuAvgValues); @@ -419,6 +428,115 @@ namespace AutoNotificatPhone.Models ); } + /// + /// 检查Kafka入库心跳(PostgreSQL) + /// + private async Task CheckKafkaHeartbeatAsync() + { + try + { + string? connectionString = BuildPostgresConnectionString(); + if (string.IsNullOrWhiteSpace(connectionString)) + { + logger.Error("Postgres配置缺失,无法检查Kafka入库心跳"); + return; + } + + await using var connection = new NpgsqlConnection(connectionString); + await connection.OpenAsync(); + + const string sql = "select ts_ms from heartbeat.heartbeat_events order by ts_ms desc limit 1"; + await using var command = new NpgsqlCommand(sql, connection); + object? result = await command.ExecuteScalarAsync(); + + if (result == null || result == DBNull.Value) + { + ExecuteKafkaInactiveAlert(); + return; + } + + if (!long.TryParse(result.ToString(), out long lastTsMs)) + { + logger.Error("Kafka入库心跳ts_ms解析失败"); + return; + } + + long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + if (nowMs - lastTsMs > TimeSpan.FromMinutes(5).TotalMilliseconds) + { + ExecuteKafkaInactiveAlert(); + } + } + catch (Exception ex) + { + logger.Error($"Kafka入库心跳检查错误: {ex.Message}"); + } + await Task.CompletedTask; + } + + /// + /// 生成PostgreSQL连接字符串 + /// + private string? BuildPostgresConnectionString() + { + IConfigurationSection section = _configuration.GetSection("Postgres"); + string? host = section["Host"]; + string? portString = section["Port"]; + string? database = section["Database"]; + string? username = section["User"]; + string? password = section["Password"]; + string? maxConnectionsString = section["MaxConnections"]; + string? idleTimeoutMsString = section["IdleTimeoutMs"]; + + if (string.IsNullOrWhiteSpace(host) || + string.IsNullOrWhiteSpace(portString) || + string.IsNullOrWhiteSpace(database) || + string.IsNullOrWhiteSpace(username) || + string.IsNullOrWhiteSpace(password)) + { + return null; + } + + if (!int.TryParse(portString, out int port)) + { + return null; + } + + var builder = new NpgsqlConnectionStringBuilder + { + Host = host, + Port = port, + Database = database, + Username = username, + Password = password + }; + + if (int.TryParse(maxConnectionsString, out int maxConnections) && maxConnections > 0) + { + builder.MaxPoolSize = maxConnections; + } + + if (int.TryParse(idleTimeoutMsString, out int idleTimeoutMs) && idleTimeoutMs > 0) + { + builder.ConnectionIdleLifetime = Math.Max(1, idleTimeoutMs / 1000); + } + + return builder.ConnectionString; + } + + /// + /// 执行Kafka入库失活警报 + /// + private void ExecuteKafkaInactiveAlert() + { + SendAlert( + smsContent: "[BLV运维提示] BLS数据库5分钟内入库数据为0。", + callContent: "BLV运维提示 BLS数据库5分钟内入库数据为0", + alertType: "BLS-数据库入库警报", + extendedDeadline: true + ); + } + /// /// 解析CPU值字符串为整数列表 /// diff --git a/Properties/PublishProfiles/FolderProfile1.pubxml b/Properties/PublishProfiles/FolderProfile1.pubxml new file mode 100644 index 0000000..be8de9c --- /dev/null +++ b/Properties/PublishProfiles/FolderProfile1.pubxml @@ -0,0 +1,20 @@ + + + + + true + false + true + Release + Any CPU + FileSystem + bin\Release\net8.0\publish\ + FileSystem + <_TargetId>Folder + + net8.0 + win-x64 + 40394cc0-be9d-457f-b0e8-115fcfbaaf85 + false + + \ No newline at end of file diff --git a/appsettings.json b/appsettings.json index 10f68b8..a5803eb 100644 --- a/appsettings.json +++ b/appsettings.json @@ -5,5 +5,14 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "Postgres": { + "Host": "10.8.8.109", + "Port": "5433", + "Database": "log_platform", + "User": "log_admin", + "Password": "YourActualStrongPasswordForPostgres!", + "MaxConnections": "2", + "IdleTimeoutMs": "30000" + } } diff --git a/config.md b/config.md new file mode 100644 index 0000000..0eb64c8 --- /dev/null +++ b/config.md @@ -0,0 +1,7 @@ +POSTGRES_HOST=10.8.8.109 +POSTGRES_PORT=5433 +POSTGRES_DATABASE=log_platform +POSTGRES_USER=log_admin +POSTGRES_PASSWORD=YourActualStrongPasswordForPostgres! +POSTGRES_MAX_CONNECTIONS=2 +POSTGRES_IDLE_TIMEOUT_MS=30000 \ No newline at end of file