guanghulab/skyeye/scripts/optimizer.js
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

210 lines
6.2 KiB
JavaScript

#!/usr/bin/env node
/**
* skyeye/scripts/optimizer.js
* 天眼动态调优引擎 — 基于配额使用情况自动调整 Guard 触发频率
* Phase 3 of weekly scan: Optimize Guards
*/
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const SKYEYE_DIR = path.resolve(__dirname, '..');
const GUARDS_DIR = path.join(SKYEYE_DIR, 'guards');
const LEDGER_PATH = path.join(SKYEYE_DIR, 'quota-ledger.json');
const LOGS_DIR = path.join(SKYEYE_DIR, 'logs');
function getTimestamp() {
return new Date().toISOString();
}
function getDateStr() {
return new Date().toISOString().slice(0, 10).replace(/-/g, '');
}
function loadJSON(filePath) {
try {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
function saveJSON(filePath, data) {
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function calculateUsagePercent(guard) {
const qp = guard.quota_policy;
if (!qp || !qp.monthly_limit || qp.monthly_limit === 0) return 0;
return Math.round(((qp.current_month_used || 0) / qp.monthly_limit) * 100 * 10) / 10;
}
const OPTIMIZATION_RULES = [
{
name: 'quota_warning_reduce_frequency',
condition: (guard) => {
const pct = calculateUsagePercent(guard);
return pct > 70 && pct <= 90;
},
action: (guard) => {
const prev = guard.trigger_policy.default_frequency;
guard.trigger_policy.default_frequency = guard.trigger_policy.min_frequency;
return {
rule: 'quota_warning_reduce_frequency',
guard_id: guard.guard_id,
action: 'reduce_frequency',
detail: `配额超 70%,频率从 ${prev} 降至 ${guard.trigger_policy.min_frequency}`,
previous: prev,
current: guard.trigger_policy.min_frequency
};
}
},
{
name: 'quota_critical_emergency_only',
condition: (guard) => {
const pct = calculateUsagePercent(guard);
return pct > 90;
},
action: (guard) => {
const prevMode = guard.mode;
guard.mode = 'emergency_only';
return {
rule: 'quota_critical_emergency_only',
guard_id: guard.guard_id,
action: 'switch_to_emergency',
detail: `配额超 90%,切换至仅紧急模式`,
previous_mode: prevMode,
current_mode: 'emergency_only'
};
}
},
{
name: 'health_check_failures_suspend',
condition: (guard) => {
return guard.health_check && guard.health_check.consecutive_failures >= 3;
},
action: (guard) => {
const prevMode = guard.mode;
guard.mode = 'suspended';
return {
rule: 'health_check_failures_suspend',
guard_id: guard.guard_id,
action: 'suspend',
detail: `连续 ${guard.health_check.consecutive_failures} 次健康检查失败,已暂停`,
previous_mode: prevMode,
current_mode: 'suspended'
};
}
},
{
name: 'backlog_increase_frequency',
condition: (guard) => {
const pct = calculateUsagePercent(guard);
const pending = guard.buffer_policy && guard.buffer_policy.pending_count;
return pending > 100 && pct < 50;
},
action: (guard) => {
const prev = guard.trigger_policy.default_frequency;
guard.trigger_policy.default_frequency = guard.trigger_policy.max_frequency;
return {
rule: 'backlog_increase_frequency',
guard_id: guard.guard_id,
action: 'increase_frequency',
detail: `消息积压 ${guard.buffer_policy.pending_count} 条,配额充裕,已加频`,
previous: prev,
current: guard.trigger_policy.max_frequency
};
}
}
];
function optimizeGuard(guard) {
const adjustments = [];
for (const rule of OPTIMIZATION_RULES) {
if (rule.condition(guard)) {
const adjustment = rule.action(guard);
adjustments.push(adjustment);
// Critical/emergency rules take priority - stop processing
if (rule.name === 'quota_critical_emergency_only' || rule.name === 'health_check_failures_suspend') {
break;
}
}
}
if (adjustments.length > 0) {
guard.last_updated_by = 'skyeye-optimizer';
guard.last_updated_at = getTimestamp();
}
return adjustments;
}
function run() {
const args = process.argv.slice(2);
const applyChanges = args.includes('--apply');
console.log(`[SkyEye Optimizer] Mode: ${applyChanges ? 'apply' : 'dry-run'}`);
console.log(`[SkyEye Optimizer] Timestamp: ${getTimestamp()}`);
const optimizeResult = {
optimize_id: `OPT-${getDateStr()}`,
timestamp: getTimestamp(),
mode: applyChanges ? 'apply' : 'dry-run',
guards_checked: 0,
adjustments: [],
summary: {}
};
const guardFiles = fs.readdirSync(GUARDS_DIR)
.filter(f => f.endsWith('.json') && f !== 'guard-template.json');
for (const file of guardFiles) {
const filePath = path.join(GUARDS_DIR, file);
const guard = loadJSON(filePath);
if (!guard) {
console.warn(`[SkyEye Optimizer] WARNING: Cannot load ${file}`);
continue;
}
optimizeResult.guards_checked++;
const adjustments = optimizeGuard(guard);
if (adjustments.length > 0) {
optimizeResult.adjustments.push(...adjustments);
if (applyChanges) {
saveJSON(filePath, guard);
console.log(` [APPLIED] ${file}: ${adjustments.length} adjustment(s)`);
} else {
console.log(` [DRY-RUN] ${file}: ${adjustments.length} adjustment(s) would be applied`);
}
} else {
console.log(` [OK] ${file}: no adjustments needed`);
}
}
optimizeResult.summary = {
guards_checked: optimizeResult.guards_checked,
total_adjustments: optimizeResult.adjustments.length,
applied: applyChanges
};
// Write log
const logDir = path.join(LOGS_DIR, 'weekly');
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
const logPath = path.join(logDir, `optimize-${getDateStr()}.json`);
saveJSON(logPath, optimizeResult);
console.log(`[SkyEye Optimizer] Guards checked: ${optimizeResult.guards_checked}`);
console.log(`[SkyEye Optimizer] Adjustments: ${optimizeResult.adjustments.length}`);
console.log(`[SkyEye Optimizer] Log saved: ${logPath}`);
console.log('---OPTIMIZE_RESULT_JSON---');
console.log(JSON.stringify(optimizeResult, null, 2));
return optimizeResult;
}
run();