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',
' node scripts/runtime-slo-report.mjs',
' 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',
' node scripts/runtime-worker-drain.mjs drain 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}"
MINUTE="${MEMIND_RUNTIME_SLO_MINUTE:-55}"
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"
@@ -34,6 +35,9 @@ cat > "$PLIST" <<EOF
<string>$NODE_BIN</string>
<string>$SCRIPT</string>
<string>--write-report</string>
<string>--prune</string>
<string>--retention-days</string>
<string>$RETENTION_DAYS</string>
<string>--report-dir</string>
<string>$REPORT_DIR</string>
</array>
@@ -69,4 +73,5 @@ echo "installed $PLIST"
echo "script: $SCRIPT"
echo "schedule: daily ${HOUR}:${MINUTE}"
echo "report_dir: $REPORT_DIR"
echo "retention_days: $RETENTION_DAYS"
echo "log: $LOG"
+78 -3
View File
@@ -90,27 +90,85 @@ function uniquePaths(paths) {
function parseArgs(argv) {
const args = {
writeReport: false,
prune: false,
retentionDays: Number(process.env.MEMIND_RUNTIME_SLO_RETENTION_DAYS || 30),
reportDir: process.env.MEMIND_RUNTIME_REPORT_DIR || '',
};
for (let i = 0; i < argv.length; i += 1) {
const item = argv[i];
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 === '--help' || item === '-h') args.help = true;
}
if (!Number.isFinite(args.retentionDays) || args.retentionDays < 1) {
throw new Error(`Invalid --retention-days: ${args.retentionDays}`);
}
return args;
}
function printHelp() {
console.log([
'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.',
'--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'));
}
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() {
return [
['h5_users', 'users'],
@@ -257,6 +315,17 @@ if (runtimeSummary?.toolQueue?.inFlight > runtimeSummary?.toolQueue?.maxConcurre
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 = {
ok: failures.length === 0,
checkedAt: new Date().toISOString(),
@@ -274,7 +343,9 @@ const report = {
mindSpace: false,
redis: false,
report: Boolean(args.writeReport),
reportPrune: Boolean(args.prune),
},
reportPrune,
};
function markdownReport(payload) {
@@ -319,13 +390,17 @@ function markdownReport(payload) {
JSON.stringify(payload.writes, null, 2),
'```',
'',
'## Report Prune',
'',
'```json',
JSON.stringify(payload.reportPrune ?? null, null, 2),
'```',
'',
);
return lines.join('\n');
}
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, '-');
report.reportFiles = {
json: path.join(reportDir, `${stamp}.json`),