fix(backup): terapkan restore DB saat startup (tunda swap) - menimpa DB di bawah koneksi hidup merusak (WAL)
This commit is contained in:
1 parent
2aadb66f77
commit
ba0845da47
2 files changed
+28
-11
No files matched your search
@@ -10,6 +10,26 @@ if (!fs.existsSync(dbDir)) fs.mkdirSync(dbDir, { recursive: true });
|
|||||||
|
|
||||||
const dbPath = path.join(dbDir, 'billing.db');
|
const dbPath = path.join(dbDir, 'billing.db');
|
||||||
|
|
||||||
|
// Terapkan restore DB yang ditunda SEBELUM koneksi dibuka.
|
||||||
|
// (menimpa billing.db di bawah koneksi hidup bisa merusak DB karena WAL bercampur)
|
||||||
|
const _pendingRestore = path.join(dbDir, '.restore-pending');
|
||||||
|
if (fs.existsSync(_pendingRestore)) {
|
||||||
|
try {
|
||||||
|
const _bkName = fs.readFileSync(_pendingRestore, 'utf8').trim();
|
||||||
|
const _bkPath = path.join(__dirname, '..', 'backups', _bkName);
|
||||||
|
if (_bkName && fs.existsSync(_bkPath)) {
|
||||||
|
fs.copyFileSync(_bkPath, dbPath);
|
||||||
|
for (const _ext of ['-wal', '-shm']) { try { fs.unlinkSync(dbPath + _ext); } catch (e) {} }
|
||||||
|
console.log('[DB] Restore tertunda diterapkan dari ' + _bkName);
|
||||||
|
} else {
|
||||||
|
console.error('[DB] Restore tertunda dilewati, backup tidak ada: ' + _bkName);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[DB] Gagal menerapkan restore tertunda:', e.message);
|
||||||
|
}
|
||||||
|
try { fs.unlinkSync(_pendingRestore); } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
let db;
|
let db;
|
||||||
try {
|
try {
|
||||||
db = new Database(dbPath);
|
db = new Database(dbPath);
|
||||||
|
|||||||
@@ -140,22 +140,19 @@ function restoreDatabase(backupFileName) {
|
|||||||
logger.warn('[Backup] Failed to create pre-restore backup');
|
logger.warn('[Backup] Failed to create pre-restore backup');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore database
|
// Tunda restore ke saat startup: menimpa DB di bawah koneksi hidup bisa merusak (WAL bercampur).
|
||||||
fs.copyFileSync(backupFilePath, dbPath);
|
// Penanda dibaca config/database.js saat boot, sebelum koneksi dibuka.
|
||||||
// Buang WAL/SHM lama: backup VACUUM INTO self-contained, WAL lama milik DB sebelumnya
|
const pendingPath = path.join(projectRoot, 'database', '.restore-pending');
|
||||||
for (const ext of ['-wal', '-shm']) {
|
fs.writeFileSync(pendingPath, backupFileName, 'utf8');
|
||||||
try { fs.unlinkSync(dbPath + ext); } catch (e) {}
|
const size = fs.statSync(backupFilePath).size;
|
||||||
}
|
|
||||||
|
|
||||||
const stats = fs.statSync(dbPath);
|
logger.info(`[Backup] Restore dijadwalkan (diterapkan saat restart): ${backupFileName}`);
|
||||||
const sizeKB = Math.round(stats.size / 1024);
|
|
||||||
|
|
||||||
logger.info(`[Backup] Database restored from: ${backupFileName} (${sizeKB} KB)`);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
fileName: backupFileName,
|
fileName: backupFileName,
|
||||||
size: stats.size,
|
size,
|
||||||
|
pendingRestart: true,
|
||||||
timestamp: getNowLocalISO(),
|
timestamp: getNowLocalISO(),
|
||||||
preRestoreBackup: preRestoreBackup.fileName
|
preRestoreBackup: preRestoreBackup.fileName
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in new issue
Block a user