将Kafka检查跳过时段结束时间从4点延长至5点,并将数据库连接失败告警触发阈值从8次提高到10次,以减少误告警
Web_AutoNotificatPhone_Server_Prod
1. 项目概述
这是一个基于 ASP.NET Core 8 MVC 的通知与巡检服务,核心职责是:
- 提供 HTTP API,接收“电话/短信”通知请求并发布到 Redis 频道。
- 运行后台定时任务(
TimerClass),每分钟做系统状态检查。 - 根据 Redis 指标和 PostgreSQL 心跳数据触发自动告警(短信 + 电话)。
项目本质上是一个“告警编排层”:
- 输入来源:HTTP 请求、Redis 指标、PostgreSQL 心跳表。
- 输出目标:Redis 发布(供下游呼叫/短信系统消费)。
2. 技术栈与依赖
- .NET:
net8.0 - Web: ASP.NET Core MVC + API Controller
- Redis:
CSRedisCore - PostgreSQL:
Npgsql - Logging:
NLog
AutoNotificatPhone.csproj 关键包:
CSRedisCoreNLogNpgsql
3. 目录与核心文件
Program.cs:应用启动、CORS、路由、HostedService 注册。Controllers/CallAndMsgController.cs:通知入站 API(电话/短信)。Models/TimerClass.cs:后台巡检与告警主流程。CSRedisCacheHelper.cs:Redis 连接与基础操作封装。Models/SmsRequest.cs:通知请求模型。Models/ReturnInfo.cs:统一接口返回结构。appsettings.json:日志级别、Postgres 连接配置。nlog.config:日志落盘规则。
4. 启动流程(程序生命周期)
4.1 Program 启动阶段
Program.cs 主要行为:
AddControllersWithViews():注册 MVC 和 API 支持。- 注册 CORS 策略
AllowAnyOrigin:- 允许任意源
- 允许任意方法
- 允许任意请求头
AddHostedService<TimerClass>():注册后台巡检服务。- 管道顺序:
UseStaticFiles()UseRouting()UseCors("AllowAnyOrigin")UseAuthorization()MapControllerRoute(...)
4.2 后台服务启动
应用启动后,TimerClass 自动运行:
- 持续循环,直到应用停止。
- 每分钟固定在第 30 秒执行一次巡检逻辑。
5. API 处理流程(CallAndMsgController)
5.1 路由
Controller 路由前缀:
api/CallAndMsg/{action}
核心接口:
POST api/CallAndMsg/SendToPhone
5.2 请求模型(SmsRequest)
PhoneNumber:目标手机号CallerName:任务标识/来电显示名Content:消息内容StartingPoint:开始时间(Unix 秒)DeadLine:截止时间(Unix 秒)Type:1电话,2短信
5.3 接口执行逻辑
SendToPhone 内部流程:
- 接收
SmsRequest。 - 组装
notification对象。 - 使用固定频道
MsgAndCall发布到 Redis:CSRedisCacheHelper.Publish("MsgAndCall", payload)
- 返回
ReturnInfo:- 成功:
status=200+ 根据Type返回“已加入队列”文案 - 失败:
status=500+ 异常信息
- 成功:
说明:
ConvertTimestampToIso名称为“转 ISO”,但实际仍返回 Unix 秒。
6. Redis 封装(CSRedisCacheHelper)
6.1 连接
静态初始化时连接本地 Redis:
- Host:
127.0.0.1 - Port:
10079 - 密码:代码中硬编码
- DB0:
redis - DB1:
redis1
6.2 用途
DB0:主要用于发布通知频道(MsgAndCall)。DB1:主要用于读取巡检指标(CPU、在线数、收发包等)。
6.3 方法
Set/Get/Forever/Del/ContainsPublish
7. 核心:TimerClass 业务流程详解
TimerClass 是项目核心,分为 调度层、检查层、告警层。
7.1 调度层(每分钟触发)
主循环执行顺序:
- 计算下次执行时间(每分钟第 30 秒)。
- 检查电话机进程是否在线(进程名
Telephone)。 - 运行整点任务调度。
- 依次执行检查任务:
- CPU 阈值
- RCU 在线数量
- 总发送包
- 总接收包
- PostgreSQL 心跳
出现异常时:
- 记录日志
- 延迟 10 秒重试
7.2 整点任务调度
方法:RunHourlyNotificationTask()
规则:
- 使用北京时间(UTC+8)。
- 非整点(
Minute != 0)不执行。 - 同一整点只执行一次(
_executedTasks去重)。 - 10/15/22 点执行每日任务,其余整点发整点短信。
7.2.1 整点短信(SendHourlySms)
- 给
Mobile1发送一条短信任务。 - 文案包含当前“月/日/时”。
7.2.2 每日任务(ExecuteDailyTask)
- 给
Mobile1和Mobile2发送短信。 - 给
Mobile1发送电话任务。 - 任意发送失败记录错误日志。
7.3 Redis 指标检查
7.3.1 CPU 检查(CheckCpuThreshold)
步骤:
- 读取
UDPPackage_DetectTime:- 若超过 10 分钟未更新,触发“监控程序无法访问”告警。
- 读取:
UDPPackage_CPUMaxUDPPackage_CPUAvgUDPPackage_CPUMin
- 若
CPUAvg中满足“>=80 的点数达到 6 个”,触发 CPU 告警。
7.3.2 通用 Redis 规则(CheckRedisValue)
用于在线数/发送包/接收包的基线跌落判断:
- 读取 CSV 序列。
- 取前
baselineCount个点做平均。 - 阈值 = 平均值 ×
thresholdRatio。 - 若后续两个点都低于阈值,触发告警。
具体调用:
RCUOnLine:baselineCount=8,ratio=0.8UDPPackage_TotalSendPackage:baselineCount=8,ratio=0.6UDPPackage_TotalRecvPackage:baselineCount=8,ratio=0.75
7.3.3 接收包特殊规则(CheckTotalRecvPackage)
在通用规则之前,先判断:
- 若最后 3 个值都
< 70000,立即触发告警。
7.4 PostgreSQL 心跳检查
方法:CheckKafkaHeartbeatAsync()
目标:判断“Kafka 入库是否活跃”。
流程:
- 从
appsettings.json的Postgres节生成连接串。 - 查询
heartbeat.heartbeat_events:- 先按
ts_ms desc取最近 3000 条 - 再按
write_ts_ms desc取最新一条
- 先按
- 结果为空或解析失败:走“数据库连接失败”告警路径。
- 若
nowMs - lastTsMs > KafkaStaleMinutes:触发“入库停滞”告警。 - 异常(连接失败/SQL 异常)同样走“数据库连接失败”告警。
7.4.1 数据库连接失败节流
- 字段:
_kafkaDbConnectionAlertCount - 逻辑:失败累计到
KafkaDbAlertTriggerCount=8才真正发一次告警,之后计数清零。
8. 告警发送机制
统一通过 SendAlert(...):
- 计算过期时间:
- 普通:短信 1800 秒、电话 900 秒
- 扩展:短信 3600 秒、电话 1800 秒
- 构造 3 条任务:
- 短信:
Mobile1 - 短信:
Mobile2 - 电话:
Mobile1
- 短信:
- 调用
CallAndMsgController.SendToPhone投递。 - 任一失败,记录错误日志。
9. 配置说明
9.1 appsettings.json
当前包含:
LoggingAllowedHostsPostgresHostPortDatabaseUserPasswordMaxConnectionsIdleTimeoutMs
9.2 nlog.config
- 文件落盘目录:
{basedir}/Logs/{shortdate} - 文件:
info_*.txt、error_*.txt - 当前规则:
FATAL写入 info 文件Error及以上写入 error 文件
10. 快速运行
10.1 开发运行
dotnet restore
dotnet build AutoNotificatPhone.csproj
dotnet run --project AutoNotificatPhone.csproj
默认开发地址见 Properties/launchSettings.json:
http://localhost:5080
10.2 VS Code Tasks
项目已配置任务:
buildpublishwatch
11. 对外接口示例
请求:
POST /api/CallAndMsg/SendToPhone
Content-Type: application/json
{
"PhoneNumber": "13500000000",
"CallerName": "测试任务",
"Content": "测试短信内容",
"StartingPoint": 1760000000,
"DeadLine": 1760001800,
"Type": "2"
}
成功响应:
{
"isok": true,
"message": "短信已加入发送队列",
"status": 200,
"response": "success"
}
12. 关键数据流(一句话版)
外部请求/定时巡检 -> 生成 SmsRequest -> CallAndMsgController -> Redis 频道 MsgAndCall -> 下游系统消费执行。
13. 当前实现中的注意点
CallAndMsgController中ConvertTimestampToIso命名与实现含义不一致(返回 Unix 秒)。CSRedisCacheHelper中 Redis 密码硬编码在代码,不利于安全与环境切换。TimerClass的KafkaStaleMinutes与告警文案“3分钟内入库数据为0”存在语义不一致风险(建议统一)。- 当前 CORS 为完全放开,生产环境建议收敛来源。
14. 后续可优化方向(可选)
- 将手机号、阈值、执行小时、告警文案全部配置化。
- 让
TimerClass通过接口服务发送通知,避免直接 new Controller。 - 增加单元测试:
- Redis 阈值计算
- Kafka 心跳判定
- 告警节流逻辑
- 增加健康检查端点(数据库/Redis 连通性)。
15. 维护建议
每次修改巡检规则后,至少验证:
dotnet build无编译错误。- Redis 有模拟数据时告警触发正确。
- PostgreSQL 心跳超时/失败路径可复现。
MsgAndCall频道消息格式未破坏下游兼容。
Description
Languages
C#
87.8%
HTML
8.9%
CSS
2.8%
JavaScript
0.5%