// 预警检查服务 - 定时任务调用 const { v4: uuidv4 } = require('uuid'); const notificationService = require('./notification'); // 模拟数据库 const db = { alertRules: [ // 示例规则,实际从数据库读取 { id: 'rule-1', name: '日销售额低于警戒线', cubeName: 'Orders', measureName: 'Orders.totalAmount', dimension: 'Orders.orderDate', condition: 'lt', threshold: 100000, timeGranularity: 'day', timeRange: 'Today', notifyChannels: ['wechat', 'dingtalk'], severity: 'high', status: 'active', }, { id: 'rule-2', name: '订单取消率超标', cubeName: 'Orders', measureName: 'Orders.cancelRate', dimension: 'Orders.orderDate', condition: 'gt', threshold: 0.05, timeGranularity: 'day', timeRange: 'Last 7 days', notifyChannels: ['dingtalk'], severity: 'critical', status: 'active', }, ], alertRecords: [], notificationChannels: [], }; class AlertChecker { constructor() { this.cubejsApi = null; } // 设置 Cube.js API 实例 setCubeJsApi(api) { this.cubejsApi = api; } // 获取所有启用的规则 async getActiveRules() { return db.alertRules.filter(r => r.status === 'active'); } // 检查所有规则 async checkAllRules() { const rules = await this.getActiveRules(); const results = []; for (const rule of rules) { const result = await this.checkRule(rule); results.push(result); } console.log(`🔔 预警检查完成: ${results.filter(r => r.triggered).length} 条触发`); return results; } // 检查单条规则 async checkRule(rule) { try { const query = this.buildQuery(rule); const currentValue = await this.executeQuery(query); const isTriggered = this.evaluateCondition(currentValue, rule.condition, rule.threshold); if (isTriggered) { await this.triggerAlert(rule, currentValue); } return { ruleId: rule.id, ruleName: rule.name, triggered: isTriggered, value: currentValue, threshold: rule.threshold, checkedAt: new Date().toISOString(), }; } catch (error) { console.error(`⚠️ 规则检查失败 [${rule.name}]:`, error.message); return { ruleId: rule.id, ruleName: rule.name, error: error.message, checkedAt: new Date().toISOString(), }; } } // 构建查询 buildQuery(rule) { return { measures: [rule.measureName], timeDimensions: [ { dimension: rule.dimension, granularity: rule.timeGranularity, dateRange: rule.timeRange, }, ], filters: rule.dimensionFilter || [], limit: 1, }; } // 执行查询(模拟,实际调用 Cube.js API) async executeQuery(query) { // 如果没有设置 Cube.js API,返回模拟数据用于测试 if (!this.cubejsApi) { // 模拟查询结果 return Math.random() * 200000; // 随机生成一个值用于测试 } try { const result = await this.cubejsApi.load(query); const data = result.data || []; if (data.length > 0) { const firstRow = data[0]; // 获取 measures 中的第一个指标值 const measureKey = Object.keys(firstRow).find(k => k.startsWith(query.measures[0].split('.')[0])); return firstRow[measureKey] || 0; } return 0; } catch (error) { throw new Error(`查询失败: ${error.message}`); } } // 条件判断 evaluateCondition(value, condition, threshold) { switch (condition) { case 'gt': return value > threshold; case 'lt': return value < threshold; case 'eq': return value === threshold; case 'gte': return value >= threshold; case 'lte': return value <= threshold; default: return false; } } // 触发预警 async triggerAlert(rule, currentValue) { // 检查是否已触发(避免重复通知) const recentRecord = db.alertRecords.find(r => { return ( r.ruleId === rule.id && r.status === 'triggered' && new Date() - new Date(r.triggeredAt) < 30 * 60 * 1000 // 30分钟内不重复 ); }); if (recentRecord) { console.log(`⏭️ 跳过重复预警 [${rule.name}]`); return; } // 获取订阅用户 const subscribers = await this.getSubscribers(rule.id); // 发送通知 const message = notificationService.formatAlertMessage(rule, currentValue, rule.threshold); const notificationResults = await notificationService.sendToUsers( subscribers.map(s => s.userId), message, rule.notifyChannels ); // 记录预警 const record = { id: uuidv4(), ruleId: rule.id, triggeredAt: new Date().toISOString(), actualValue: currentValue, threshold: rule.threshold, status: 'triggered', notifiedChannels: rule.notifyChannels, notificationResults, }; db.alertRecords.push(record); console.log(`🚨 预警已触发 [${rule.name}]: 值=${currentValue}, 阈值=${rule.threshold}`); console.log(` 通知渠道: ${rule.notifyChannels.join(', ')}`); return record; } // 获取订阅用户 async getSubscribers(ruleId) { // 实际项目中应从数据库查询 // 这里返回管理员用户 return [ { userId: 'admin-1', role: 'admin' }, ]; } // 获取预警记录 getAlertRecords(filters = {}) { let records = [...db.alertRecords]; if (filters.ruleId) { records = records.filter(r => r.ruleId === filters.ruleId); } if (filters.status) { records = records.filter(r => r.status === filters.status); } return records.sort((a, b) => new Date(b.triggeredAt) - new Date(a.triggeredAt)); } } module.exports = new AlertChecker();