feat(backup): add MinIO snapshot backups via CLI and scheduler

This commit is contained in:
William Valentin
2026-02-16 13:16:29 -08:00
parent 8bed99c770
commit 01ee6ba53f
13 changed files with 416 additions and 1 deletions
+34
View File
@@ -33,6 +33,7 @@ import type { McpManager } from '../mcp/index.js';
import type { SkillRegistry, SkillInstaller } from '../skills/index.js';
import type { GatewayServer } from '../gateway/index.js';
import { AuditLogger, initAuditLogger } from '../audit/index.js';
import { runBackupSnapshot } from '../backup/index.js';
export interface DaemonContext {
config: Config;
@@ -103,6 +104,39 @@ export async function startDaemon(config: Config, options?: StartDaemonOptions):
lifecycle.onShutdown(async () => { clearInterval(pruneInterval); });
}
if (config.backup.enabled) {
const backupIntervalMs = parseDuration(config.backup.interval);
if (!backupIntervalMs) {
console.warn(`Backup enabled but interval is invalid: ${config.backup.interval}`);
} else {
let backupRunning = false;
const runScheduledBackup = async (): Promise<void> => {
if (backupRunning) {
return;
}
backupRunning = true;
try {
const result = await runBackupSnapshot({
dataDir,
backupConfig: config.backup,
});
console.log(`Backup completed: ${result.archivePath}${result.uploaded && result.remotePath ? ` -> ${result.remotePath}` : ''}`);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`Backup failed: ${message}`);
} finally {
backupRunning = false;
}
};
const backupInterval = setInterval(() => {
void runScheduledBackup();
}, backupIntervalMs);
lifecycle.onShutdown(async () => { clearInterval(backupInterval); });
console.log(`Backup scheduler enabled (${config.backup.interval})`);
}
}
// ── Core Services ──
const hookEngine = new HookEngine(config.hooks);
const { toolRegistry, toolExecutor, browserManager } = initTools({ config, lifecycle, hookEngine });