chore: prune runtime slo reports

This commit is contained in:
John
2026-07-02 08:38:56 +08:00
parent bb98734d9c
commit 8a53dff856
3 changed files with 84 additions and 3 deletions
+1
View File
@@ -367,6 +367,7 @@ async function writeMetadata() {
' bash scripts/install-runtime-metrics-agent.sh', ' bash scripts/install-runtime-metrics-agent.sh',
' node scripts/runtime-slo-report.mjs', ' node scripts/runtime-slo-report.mjs',
' node scripts/runtime-slo-report.mjs --write-report', ' node scripts/runtime-slo-report.mjs --write-report',
' node scripts/runtime-slo-report.mjs --write-report --prune --retention-days 30',
' bash scripts/install-runtime-slo-report-agent.sh', ' bash scripts/install-runtime-slo-report-agent.sh',
' node scripts/runtime-worker-drain.mjs drain goosed-3', ' node scripts/runtime-worker-drain.mjs drain goosed-3',
' node scripts/runtime-worker-drain.mjs undrain goosed-3', ' node scripts/runtime-worker-drain.mjs undrain goosed-3',
@@ -11,6 +11,7 @@ GUI="gui/$(id -u)"
HOUR="${MEMIND_RUNTIME_SLO_HOUR:-23}" HOUR="${MEMIND_RUNTIME_SLO_HOUR:-23}"
MINUTE="${MEMIND_RUNTIME_SLO_MINUTE:-55}" MINUTE="${MEMIND_RUNTIME_SLO_MINUTE:-55}"
REPORT_DIR="${MEMIND_RUNTIME_REPORT_DIR:-$ROOT/reports/runtime-slo}" REPORT_DIR="${MEMIND_RUNTIME_REPORT_DIR:-$ROOT/reports/runtime-slo}"
RETENTION_DAYS="${MEMIND_RUNTIME_SLO_RETENTION_DAYS:-30}"
mkdir -p "$HOME/Library/LaunchAgents" "$HOME/Library/Logs" "$REPORT_DIR" mkdir -p "$HOME/Library/LaunchAgents" "$HOME/Library/Logs" "$REPORT_DIR"
@@ -34,6 +35,9 @@ cat > "$PLIST" <<EOF
<string>$NODE_BIN</string> <string>$NODE_BIN</string>
<string>$SCRIPT</string> <string>$SCRIPT</string>
<string>--write-report</string> <string>--write-report</string>
<string>--prune</string>
<string>--retention-days</string>
<string>$RETENTION_DAYS</string>
<string>--report-dir</string> <string>--report-dir</string>
<string>$REPORT_DIR</string> <string>$REPORT_DIR</string>
</array> </array>
@@ -69,4 +73,5 @@ echo "installed $PLIST"
echo "script: $SCRIPT" echo "script: $SCRIPT"
echo "schedule: daily ${HOUR}:${MINUTE}" echo "schedule: daily ${HOUR}:${MINUTE}"
echo "report_dir: $REPORT_DIR" echo "report_dir: $REPORT_DIR"
echo "retention_days: $RETENTION_DAYS"
echo "log: $LOG" echo "log: $LOG"
+78 -3
View File
@@ -90,27 +90,85 @@ function uniquePaths(paths) {
function parseArgs(argv) { function parseArgs(argv) {
const args = { const args = {
writeReport: false, writeReport: false,
prune: false,
retentionDays: Number(process.env.MEMIND_RUNTIME_SLO_RETENTION_DAYS || 30),
reportDir: process.env.MEMIND_RUNTIME_REPORT_DIR || '', reportDir: process.env.MEMIND_RUNTIME_REPORT_DIR || '',
}; };
for (let i = 0; i < argv.length; i += 1) { for (let i = 0; i < argv.length; i += 1) {
const item = argv[i]; const item = argv[i];
if (item === '--write-report') args.writeReport = true; if (item === '--write-report') args.writeReport = true;
else if (item === '--prune') args.prune = true;
else if (item === '--retention-days') args.retentionDays = Number(argv[++i] ?? args.retentionDays);
else if (item === '--report-dir') args.reportDir = String(argv[++i] ?? args.reportDir); else if (item === '--report-dir') args.reportDir = String(argv[++i] ?? args.reportDir);
else if (item === '--help' || item === '-h') args.help = true; else if (item === '--help' || item === '-h') args.help = true;
} }
if (!Number.isFinite(args.retentionDays) || args.retentionDays < 1) {
throw new Error(`Invalid --retention-days: ${args.retentionDays}`);
}
return args; return args;
} }
function printHelp() { function printHelp() {
console.log([ console.log([
'Usage:', 'Usage:',
' node scripts/runtime-slo-report.mjs [--write-report] [--report-dir <dir>]', ' node scripts/runtime-slo-report.mjs [--write-report] [--prune] [--retention-days <days>] [--report-dir <dir>]',
'', '',
'Default behavior is read-only and writes nothing.', 'Default behavior is read-only and writes nothing.',
'--write-report writes JSON and Markdown snapshots to an operations report directory.', '--write-report writes JSON and Markdown snapshots to an operations report directory.',
'--prune deletes old .json/.md snapshots in the report directory only.',
].join('\n')); ].join('\n'));
} }
function pruneReportDir(reportDir, retentionDays) {
const resolvedDir = path.resolve(reportDir);
const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
const result = {
enabled: true,
reportDir: resolvedDir,
retentionDays,
deleted: [],
kept: 0,
skipped: 0,
errors: [],
};
let entries = [];
try {
entries = fs.readdirSync(resolvedDir, { withFileTypes: true });
} catch (err) {
result.errors.push(err instanceof Error ? err.message : String(err));
return result;
}
for (const entry of entries) {
if (!entry.isFile()) {
result.skipped += 1;
continue;
}
if (!entry.name.endsWith('.json') && !entry.name.endsWith('.md')) {
result.skipped += 1;
continue;
}
const full = path.join(resolvedDir, entry.name);
let stat = null;
try {
stat = fs.statSync(full);
} catch (err) {
result.errors.push(`${entry.name}: ${err instanceof Error ? err.message : String(err)}`);
continue;
}
if (stat.mtimeMs >= cutoffMs) {
result.kept += 1;
continue;
}
try {
fs.unlinkSync(full);
result.deleted.push(entry.name);
} catch (err) {
result.errors.push(`${entry.name}: ${err instanceof Error ? err.message : String(err)}`);
}
}
return result;
}
function tableCountQueries() { function tableCountQueries() {
return [ return [
['h5_users', 'users'], ['h5_users', 'users'],
@@ -257,6 +315,17 @@ if (runtimeSummary?.toolQueue?.inFlight > runtimeSummary?.toolQueue?.maxConcurre
failures.push('tool_queue_concurrency_exceeded'); failures.push('tool_queue_concurrency_exceeded');
} }
const reportDir = path.resolve(args.reportDir || path.join(appRoot, 'reports', 'runtime-slo'));
if (args.writeReport || args.prune) {
fs.mkdirSync(reportDir, { recursive: true });
}
const reportPrune = args.prune
? pruneReportDir(reportDir, args.retentionDays)
: { enabled: false, reportDir, retentionDays: args.retentionDays };
for (const error of reportPrune.errors ?? []) {
failures.push(`report_prune_error:${error}`);
}
const report = { const report = {
ok: failures.length === 0, ok: failures.length === 0,
checkedAt: new Date().toISOString(), checkedAt: new Date().toISOString(),
@@ -274,7 +343,9 @@ const report = {
mindSpace: false, mindSpace: false,
redis: false, redis: false,
report: Boolean(args.writeReport), report: Boolean(args.writeReport),
reportPrune: Boolean(args.prune),
}, },
reportPrune,
}; };
function markdownReport(payload) { function markdownReport(payload) {
@@ -319,13 +390,17 @@ function markdownReport(payload) {
JSON.stringify(payload.writes, null, 2), JSON.stringify(payload.writes, null, 2),
'```', '```',
'', '',
'## Report Prune',
'',
'```json',
JSON.stringify(payload.reportPrune ?? null, null, 2),
'```',
'',
); );
return lines.join('\n'); return lines.join('\n');
} }
if (args.writeReport) { if (args.writeReport) {
const reportDir = path.resolve(args.reportDir || path.join(appRoot, 'reports', 'runtime-slo'));
fs.mkdirSync(reportDir, { recursive: true });
const stamp = new Date().toISOString().replace(/[:.]/g, '-'); const stamp = new Date().toISOString().replace(/[:.]/g, '-');
report.reportFiles = { report.reportFiles = {
json: path.join(reportDir, `${stamp}.json`), json: path.join(reportDir, `${stamp}.json`),