Nightly DB snapshots to the 1TB storage box (live DB stays local)
The 'external drive' turned out to be a CIFS-mounted Hetzner storage box — SQLite cannot run on a network mount (WAL shared memory and locking break), and the live DB is only ~7MB anyway. So: the hot database stays on the local volume, and a nightly VACUUM INTO snapshot (transactionally consistent, a plain sequential file write — perfect for CIFS) lands in /data/archive, which compose binds to the storage box via HOST_ARCHIVE_DIR. 14-day retention, plus a snapshot at boot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+24
-1
@@ -1,5 +1,5 @@
|
||||
import { DatabaseSync } from 'node:sqlite';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import { mkdirSync, readdirSync, rmSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
// Persistence via Node's built-in SQLite (no native deps). One file on a Docker
|
||||
@@ -135,6 +135,29 @@ export function cacheSet(key: string, value: string, ttl: number): void {
|
||||
.run(key, value, Date.now(), ttl);
|
||||
}
|
||||
|
||||
/** Nightly consistent snapshot via VACUUM INTO (transaction-safe, works on any
|
||||
* filesystem — the archive dir may be a CIFS-mounted storage box, where the
|
||||
* LIVE database could never run). Keeps the newest `keep` dated copies. */
|
||||
export function backupDb(keep = 14): string | null {
|
||||
const dir = process.env.ARCHIVE_DIR ?? path.join(DATA_DIR, 'archive');
|
||||
try {
|
||||
mkdirSync(dir, { recursive: true });
|
||||
const stamp = new Date().toISOString().slice(0, 10);
|
||||
const dest = path.join(dir, `cup26-${stamp}.db`);
|
||||
rmSync(dest, { force: true }); // VACUUM INTO refuses to overwrite
|
||||
db().exec(`VACUUM INTO '${dest.replaceAll("'", "''")}'`);
|
||||
const files = readdirSync(dir).filter((f) => /^cup26-\d{4}-\d{2}-\d{2}\.db$/.test(f)).sort();
|
||||
for (const f of files.slice(0, Math.max(0, files.length - keep))) {
|
||||
rmSync(path.join(dir, f), { force: true });
|
||||
}
|
||||
console.log(`[db] snapshot → ${dest}`);
|
||||
return dest;
|
||||
} catch (e) {
|
||||
console.error('[db] backup failed:', e instanceof Error ? e.message : e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Bound DB growth: drop cache entries stale for >7 days (the breaker only ever
|
||||
* serves recent staleness) and ingest-log rows older than 14 days. Returns the
|
||||
* number of rows removed. Runs daily from the scheduler. */
|
||||
|
||||
Reference in New Issue
Block a user