252 lines
7.3 KiB
JavaScript
252 lines
7.3 KiB
JavaScript
/**
|
||
* ═══════════════════════════════════════════════════════════
|
||
* 🔬 活模块: SY-TEST · 系统自检
|
||
* ═══════════════════════════════════════════════════════════
|
||
*
|
||
* 编号: ZY-TASK-007 · S5 Agent系统级
|
||
* 签发: 铸渊 · ICE-GL-ZY001
|
||
* 版权: 国作登字-2026-A-00037559
|
||
*
|
||
* v2.0: 从死模块升级为活模块
|
||
* - 继承 LivingModule 基类
|
||
* - 自诊断覆盖: DB/COS/brain_nodes/agent_configs 四项检查
|
||
* - 自愈: DB断连自动重试、COS超时告警
|
||
* - 学习: 记录每次检查结果的成功/失败模式
|
||
*
|
||
* 每30分钟运行一次 · 检测全系统健康
|
||
*/
|
||
|
||
'use strict';
|
||
|
||
const LivingModule = require('./living-module');
|
||
const db = require('../mcp-server/db');
|
||
const cos = require('../mcp-server/cos');
|
||
|
||
class LivingSyTest extends LivingModule {
|
||
constructor(options = {}) {
|
||
super({
|
||
moduleId: 'ZY-MOD-SY-TEST',
|
||
name: '系统自检活模块',
|
||
moduleType: 'guard',
|
||
owner: 'zhuyuan',
|
||
db: options.db || db,
|
||
config: {
|
||
version: '2.0.0',
|
||
description: '全系统健康检测·DB/COS/表/模块',
|
||
heartbeatInterval: 60000 // 自检模块心跳1分钟
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 自定义诊断检查 — 系统全面自检
|
||
*/
|
||
async _diagnoseChecks() {
|
||
const issues = [];
|
||
|
||
// 1. 数据库连接检查
|
||
try {
|
||
const dbStatus = await db.checkConnection();
|
||
if (!dbStatus.connected) {
|
||
issues.push({
|
||
code: 'DB_DISCONNECTED',
|
||
severity: 'critical',
|
||
message: `数据库连接失败: ${dbStatus.error || '未知原因'}`,
|
||
suggestion: '检查 PostgreSQL 服务状态'
|
||
});
|
||
}
|
||
} catch (err) {
|
||
issues.push({
|
||
code: 'DB_ERROR',
|
||
severity: 'critical',
|
||
message: `数据库检查异常: ${err.message}`,
|
||
suggestion: '检查数据库配置和网络'
|
||
});
|
||
}
|
||
|
||
// 2. COS连通性检查
|
||
try {
|
||
const cosStatus = await cos.checkConnection();
|
||
if (!cosStatus.connected) {
|
||
issues.push({
|
||
code: 'COS_DISCONNECTED',
|
||
severity: 'warning',
|
||
message: `COS存储桶不可达: ${cosStatus.reason || '未知原因'}`,
|
||
suggestion: '检查 COS 密钥和网络'
|
||
});
|
||
}
|
||
} catch (err) {
|
||
issues.push({
|
||
code: 'COS_ERROR',
|
||
severity: 'warning',
|
||
message: `COS检查异常: ${err.message}`,
|
||
suggestion: '检查 COS 配置'
|
||
});
|
||
}
|
||
|
||
// 3. brain_nodes表可用性
|
||
try {
|
||
await db.query("SELECT COUNT(*) as cnt FROM brain_nodes WHERE status = 'active'");
|
||
} catch (err) {
|
||
issues.push({
|
||
code: 'TABLE_BRAIN_NODES_FAIL',
|
||
severity: 'warning',
|
||
message: `brain_nodes表不可用: ${err.message}`,
|
||
suggestion: '检查 Schema 是否已初始化'
|
||
});
|
||
}
|
||
|
||
// 4. agent_configs表可用性
|
||
try {
|
||
await db.query("SELECT COUNT(*) as cnt FROM agent_configs WHERE enabled = true");
|
||
} catch (err) {
|
||
issues.push({
|
||
code: 'TABLE_AGENT_CONFIGS_FAIL',
|
||
severity: 'warning',
|
||
message: `agent_configs表不可用: ${err.message}`,
|
||
suggestion: '检查 Schema 是否已初始化'
|
||
});
|
||
}
|
||
|
||
// 5. living_modules表可用性(S5新增)
|
||
try {
|
||
await db.query("SELECT COUNT(*) as cnt FROM living_modules WHERE status = 'alive'");
|
||
} catch (err) {
|
||
issues.push({
|
||
code: 'TABLE_LIVING_MODULES_FAIL',
|
||
severity: 'info',
|
||
message: `living_modules表不可用: ${err.message}`,
|
||
suggestion: '执行 003-living-module-tables.sql'
|
||
});
|
||
}
|
||
|
||
return issues;
|
||
}
|
||
|
||
/**
|
||
* 自愈动作
|
||
*/
|
||
async _healAction(issue) {
|
||
switch (issue.code) {
|
||
case 'DB_DISCONNECTED':
|
||
case 'DB_ERROR':
|
||
// 尝试重连
|
||
try {
|
||
await db.query('SELECT 1');
|
||
return { action: 'db_reconnect', success: true };
|
||
} catch (err) {
|
||
return { action: 'db_reconnect', success: false, error: err.message };
|
||
}
|
||
|
||
case 'COS_DISCONNECTED':
|
||
case 'COS_ERROR':
|
||
// COS问题只能上报,无法自愈
|
||
return { action: 'cos_alert_sent', success: true, details: { reported: true } };
|
||
|
||
default:
|
||
return await super._healAction(issue);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 兼容旧调度器的 run() 接口
|
||
* 调度引擎通过 run(config) 调用
|
||
*/
|
||
async function run(config) {
|
||
const checks = [];
|
||
let allPassed = true;
|
||
|
||
// 1. 数据库连接检查
|
||
try {
|
||
const dbStatus = await db.checkConnection();
|
||
checks.push({
|
||
name: '数据库连接',
|
||
status: dbStatus.connected ? 'pass' : 'fail',
|
||
detail: dbStatus.connected ? dbStatus.version : dbStatus.error
|
||
});
|
||
if (!dbStatus.connected) allPassed = false;
|
||
} catch (err) {
|
||
checks.push({ name: '数据库连接', status: 'fail', detail: err.message });
|
||
allPassed = false;
|
||
}
|
||
|
||
// 2. COS连通性检查
|
||
try {
|
||
const cosStatus = await cos.checkConnection();
|
||
checks.push({
|
||
name: 'COS存储桶',
|
||
status: cosStatus.connected ? 'pass' : 'fail',
|
||
detail: cosStatus.connected ? 'hot桶可达' : cosStatus.reason
|
||
});
|
||
if (!cosStatus.connected) allPassed = false;
|
||
} catch (err) {
|
||
checks.push({ name: 'COS存储桶', status: 'fail', detail: err.message });
|
||
allPassed = false;
|
||
}
|
||
|
||
// 3. brain_nodes表可用性
|
||
try {
|
||
const result = await db.query("SELECT COUNT(*) as cnt FROM brain_nodes WHERE status = 'active'");
|
||
checks.push({
|
||
name: 'brain_nodes表',
|
||
status: 'pass',
|
||
detail: `${result.rows[0].cnt} 个活跃节点`
|
||
});
|
||
} catch (err) {
|
||
checks.push({ name: 'brain_nodes表', status: 'fail', detail: err.message });
|
||
allPassed = false;
|
||
}
|
||
|
||
// 4. agent_configs表可用性
|
||
try {
|
||
const result = await db.query("SELECT COUNT(*) as cnt FROM agent_configs WHERE enabled = true");
|
||
checks.push({
|
||
name: 'agent_configs表',
|
||
status: 'pass',
|
||
detail: `${result.rows[0].cnt} 个启用的Agent`
|
||
});
|
||
} catch (err) {
|
||
checks.push({ name: 'agent_configs表', status: 'fail', detail: err.message });
|
||
allPassed = false;
|
||
}
|
||
|
||
// 5. living_modules表可用性(S5新增)
|
||
try {
|
||
const result = await db.query("SELECT COUNT(*) as cnt FROM living_modules WHERE status = 'alive'");
|
||
checks.push({
|
||
name: 'living_modules表',
|
||
status: 'pass',
|
||
detail: `${result.rows[0].cnt} 个活跃模块`
|
||
});
|
||
} catch (err) {
|
||
checks.push({ name: 'living_modules表', status: 'warn', detail: `未初始化: ${err.message}` });
|
||
// 不算严重失败·Schema可能还没部署
|
||
}
|
||
|
||
// 学习:如果调度引擎注入了bus,通过HLDP上报结果
|
||
if (config && config.bus) {
|
||
try {
|
||
await config.bus.send('ZY-MOD-SY-TEST', 'ZY-MOD-SCHEDULER', 'event', {
|
||
event: 'system_check_complete',
|
||
allPassed,
|
||
checkCount: checks.length,
|
||
failCount: checks.filter(c => c.status === 'fail').length
|
||
});
|
||
} catch (err) {
|
||
// 非关键·忽略
|
||
}
|
||
}
|
||
|
||
return {
|
||
message: allPassed ? '系统自检通过' : '系统自检发现异常',
|
||
details: {
|
||
all_passed: allPassed,
|
||
checks,
|
||
checked_at: new Date().toISOString()
|
||
}
|
||
};
|
||
}
|
||
|
||
module.exports = { run, LivingSyTest };
|