从一条告警到真正闭环:规则、站内信、工单与权限的整合实践

告警列表能显示数据,只是闭环的起点。把候选事件、规则判断、持久化通知、真实审批和统一入口接起来,还要处理事务时机、页内待办匹配以及不同角色的数据范围。

🎧 文章导读

统一页面之前,先统一业务事实

告警系统很容易被拆成几个互不相连的功能:设备上报一张表,通知一套接口,工单一个列表,页面再拼起来。看起来每个功能都“完成了”,真正发生告警时,却没人能回答这条记录最终有没有被处理。

这次实践先把环境告警接到既有规则、站内信和 BPM 能力,再增加统一规则与全业务告警入口。关键选择是:统一入口读取同一份规则,不复制规则数据;告警记录、通知和工单也各自保留明确职责。

从候选事件到告警闭环
图 1:规则命中后产生告警;通知和建单是两条后续分支,不能互相代替。

环境入口与统一入口维护同一规则 ID,修改备注后另一入口能够读到同一结果。统一页面不重置阈值、联动与接收人,也没有把其他业务的所有执行链路改造成环境业务的实现。

候选事件、规则命中和自动建单,是三个阶段

采集侧负责提供测量值或状态,并生成候选事件;规则侧决定启停、执行时间和阈值;只有通过判断,才生成或合并告警。

数值型与状态型不能强行套成同一语义。例如 CO 可以比较测量值与阈值,某些空调故障则由上游状态位触发。规则的“跳过通用阈值比较”标记,不是设备正在告警的状态值。

1
2
3
4
5
6
7
{
"businessType": "ENVIRONMENT",
"alarmType": "CO_HIGH",
"measuredValue": 15,
"parkId": "example-park",
"occurredAt": "2026-10-20T14:00:00+08:00"
}

上面是候选事件的脱敏概念示意,不是项目接口原样定义。事件中的园区维度很重要:规则编辑接口按园区限制访问,并不能证明运行时匹配也按园区隔离。两个入口要分别追踪和验证。

规则命中后,还要检查是否是未关闭告警的重复发生。本次已有逻辑会合并次数与最后发生时间,避免同一活动告警反复产生新工单。

告警产生也不等于自动建单。没有绑定工单联动时,它可以保持待处理;自动建单失败时,保留告警,供管理员补单。这样业务事实不会随着外围流程调用失败而消失。

通知要落库,还要选对事务时机

环境规则中的 PC 通知复用现有站内信能力:先有持久化消息,再通过 WebSocket 提醒接收人。刷新后仍能查看,点击后能标已读,并定位到目标告警。

本次在告警事务提交后发送通知,避免页面收到提醒时,目标记录尚未提交。下面是设计顺序示意:

1
2
3
4
5
// 伪代码:描述事务边界,不是完整的可靠消息实现。
transaction(() -> {
Alarm alarm = saveAlarm(event);
afterCommit(() -> sendPersistedNotice(alarm));
});

这里也存在明确边界:afterCommit 解决提交前发送的问题,不能保证进程崩溃时通知必达。原实现对失败记录日志并保留告警;如果业务要求可靠补发,还需另行评估事务消息表、重试和幂等机制,本次没有实现这一扩展。

实际接入还修复了 Redis 消息的 JSON 解码问题。原始 JSON 和被包裹成字符串的 JSON 需要按结构解析;直接删除反斜杠,会破坏嵌套内容、引号与换行。

通知跳转也不是保存一个 URL 就结束了。目标告警可能被页面上一次留下的时间或状态筛选挡住。本次在收到新的目标告警编号时重置旧筛选,后续用户手工筛选则不被反复清空。

1
2
3
4
5
{
"jumpRoute": "/alarms/environment",
"alarmCode": "EXAMPLE-ALARM-001",
"formBusinessId": "example-alarm-id"
}

这同样是示意结构。通知携带定位信息,不授予查看权限;页面查询仍须经过后端数据范围检查。

三种人、两类权限,必须分开检查

最常见的混淆是把“通知接收人”当成“流程处理人”。前者决定谁收到消息,后者由 BPM 流程节点决定;菜单和功能授权再决定能否进入页面、执行操作。

通知、工单与权限的边界
图 2:收到提醒不等于拥有处理权;能看菜单也不等于有编辑权。

角色或配置 负责回答的问题
规则接收人 谁收到站内信或其他通知
BPM 节点处理人 谁能完成当前待办
菜单与功能授权 谁可进入入口、编辑规则
告警数据范围 谁能看哪条告警、统计和导出

普通用户的告警列表还有分页问题:先把所有工单分页,再过滤出环境告警,会出现空页与总数失真。此次实现以告警业务分页为入口,再用当前页告警 ID 批量补充本人待办信息;本人待办/已办的数据收敛仍由服务端业务条件保证,不能用页内补充替代权限过滤。

统一入口验证时,还检查了列表、统计、详情、导出与写接口。前端隐藏按钮只能改善交互,后端仍要拒绝无编辑授权的直接请求。只读账号则应能查看审批历史,不能因为查询路径里含有 handle 就被粗略识别成写操作。

验收看业务证据,迁移看目标环境

“提交成功”的提示不足以证明 BPM 真正结束。本次同时核对了运行中任务消失、流程历史结束时间、业务流程状态和告警状态回写:

1
2
3
4
运行时待办:没有该实例残留任务
流程历史:结束时间非空
流程业务:已完成
告警记录:已处理,且关联原工单

这些证据必须来自同一个业务样本。直接写库的演示数据只能证明页面展示,不能证明采集、规则或审批链路。

按笔记记录,环境闭环完成了本机单园区的多角色和真实 BPM 验证;后续统一入口合并后,相关后端 41 项、前端 21 项目标测试以及构建通过。这不是整个仓库全量测试通过。环境通知阶段还记录了两条原有文案断言失败,也没有被隐去。

上线还要核对数据库迁移的执行方式。本项目采用服务器 Flyway CLI,服务启动不会自动补齐字段;规则结构、菜单和授权属于不同目标库,必须按依赖顺序检查。

一次 INSERT ... SELECT 执行成功也可能插入零行,因为它依赖的旧菜单不存在。幂等脚本则只保证“不重复”,不保证初始化对象正确:本次就曾从存量规则里的测试园区补出不需要的规则。因此上线前除了迁移历史,还要核对园区来源与预期新增资源。

原始记录尚未完成生产部署、现场设备复测及多园区运行隔离验证。统一入口的价值已经明确:让规则与记录更容易维护;完整闭环的可信度,则来自状态、权限、事务和部署证据逐项对应。

延伸阅读


本文根据 2026 年 9 月 22 日至 10 月 22 日的工程笔记整理。账号、凭证、地址和业务样本已脱敏;通用示例已在正文标明,历史验证结果以原记录为准。