chore: prune runtime slo reports
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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`),
|
||||||
|
|||||||
Reference in New Issue
Block a user