xiaoyi
3 天以前 abf1c0a35d85d38239ff5d2ed746a4e4b797c9d1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package cn.iocoder.yudao.module.bi.service.decision;
 
import cn.iocoder.yudao.module.bi.dal.dataobject.decision.BiAlertRecordDO;
import cn.iocoder.yudao.module.bi.dal.dataobject.decision.BiAlertRuleDO;
import cn.iocoder.yudao.module.bi.dal.dataobject.decision.BiKpiDefinitionDO;
import cn.iocoder.yudao.module.bi.dal.mysql.decision.BiAlertRecordMapper;
import cn.iocoder.yudao.module.bi.dal.mysql.decision.BiAlertRuleMapper;
import cn.iocoder.yudao.module.bi.dal.mysql.decision.BiKpiDefinitionMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
 
/**
 * 预警定时评估任务
 *
 * 定期扫描所有活跃预警规则,评估阈值并生成预警记录
 *
 * @author 超级管理员
 */
@Slf4j
@Component
public class AlertEvaluationTask {
 
    @Resource
    private BiAlertRuleMapper alertRuleMapper;
 
    @Resource
    private BiKpiDefinitionMapper kpiMapper;
 
    @Resource
    private BiAlertRecordMapper alertRecordMapper;
 
    @Resource
    private JdbcTemplate jdbcTemplate;
 
    /**
     * 每5分钟评估一次所有活跃规则
     */
    @Scheduled(fixedDelayString = "${bi.alert.evaluation.interval:300000}")
    public void evaluateAllAlertRules() {
        log.debug("[evaluateAllAlertRules][开始评估预警规则]");
        List<BiAlertRuleDO> rules = alertRuleMapper.selectList(
                BiAlertRuleDO::getEnabled, 1);
        if (rules.isEmpty()) {
            return;
        }
 
        for (BiAlertRuleDO rule : rules) {
            try {
                evaluateRule(rule);
            } catch (Exception e) {
                log.error("[evaluateAllAlertRules][规则 {} 评估异常]", rule.getId(), e);
            }
        }
    }
 
    private void evaluateRule(BiAlertRuleDO rule) {
        BiKpiDefinitionDO kpi = kpiMapper.selectById(rule.getKpiId());
        if (kpi == null || kpi.getStatus() == 0) {
            return;
        }
 
        // 执行 KPI 查询
        BigDecimal currentValue = executeQuery(kpi.getQuerySql());
        if (currentValue == null) {
            return;
        }
 
        // 比较阈值
        int cmp = currentValue.compareTo(rule.getThresholdValue());
        boolean triggered = switch (rule.getComparisonOperator()) {
            case ">" -> cmp > 0;
            case "<" -> cmp < 0;
            case ">=" -> cmp >= 0;
            case "<=" -> cmp <= 0;
            default -> false;
        };
 
        if (!triggered) {
            return;
        }
 
        // 检查是否已有未处理的同KPI预警(去重)
        Long existingCount = alertRecordMapper.selectCountByStatus(0);
        if (existingCount > 0) {
            List<BiAlertRecordDO> existing = alertRecordMapper.selectListByStatus(0);
            boolean dup = existing.stream().anyMatch(r -> r.getKpiId().equals(rule.getKpiId()));
            if (dup) {
                return;
            }
        }
 
        // 生成预警记录
        BiAlertRecordDO record = BiAlertRecordDO.builder()
                .ruleId(rule.getId())
                .kpiId(kpi.getId())
                .kpiCode(kpi.getCode())
                .kpiName(kpi.getName())
                .actualValue(currentValue)
                .thresholdValue(rule.getThresholdValue())
                .severity(rule.getSeverity())
                .alertMessage(String.format("%s 当前值 %s 超出阈值 %s",
                        kpi.getName(), currentValue, rule.getThresholdValue()))
                .status(0)
                .triggeredTime(LocalDateTime.now())
                .build();
        alertRecordMapper.insert(record);
        log.warn("[evaluateRule][触发预警] KPI={}, 当前值={}, 阈值={}",
                kpi.getName(), currentValue, rule.getThresholdValue());
    }
 
    private BigDecimal executeQuery(String sql) {
        if (sql == null || sql.isBlank()) {
            return null;
        }
        try {
            List<Map<String, Object>> result = jdbcTemplate.queryForList(sql);
            if (result.isEmpty()) {
                return null;
            }
            Object value = result.get(0).values().iterator().next();
            if (value instanceof Number) {
                return BigDecimal.valueOf(((Number) value).doubleValue());
            }
            return null;
        } catch (Exception e) {
            log.error("[executeQuery][SQL执行失败] {}", sql, e);
            return null;
        }
    }
 
}