refactor(db): lift db handle to long-lived singleton + close in shutdown
appDb module-scope let, getAppDb() exported getter, opened once in app.whenReady with migrator run inline, closed in shutdownCleanup before debugLog flush so WAL checkpoint completes cleanly. Unlocks IPC handlers to read/write SQLite without per-call open/close. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5465847c87
commit
c08b6fef7d
32
src/main.ts
32
src/main.ts
@ -9,6 +9,7 @@ import { compareUpdateVersions, isNewerUpdateVersion, normalizeUpdateVersion } f
|
|||||||
import { writeFileAtomicSync } from './main/infra/fs-atomic';
|
import { writeFileAtomicSync } from './main/infra/fs-atomic';
|
||||||
import { parseDuration, formatDuration, formatDurationDashed } from './main/infra/duration';
|
import { parseDuration, formatDuration, formatDurationDashed } from './main/infra/duration';
|
||||||
import { tBackend as tBackendCore, type BackendMessageKey } from './main/domain/i18n-backend';
|
import { tBackend as tBackendCore, type BackendMessageKey } from './main/domain/i18n-backend';
|
||||||
|
import type { DbHandle } from './main/infra/db';
|
||||||
import {
|
import {
|
||||||
normalizeLogin,
|
normalizeLogin,
|
||||||
normalizeAutoRecordPollSeconds,
|
normalizeAutoRecordPollSeconds,
|
||||||
@ -7206,30 +7207,32 @@ ipcMain.handle('save-video-dialog', async (_, defaultName: string) => {
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
// APP LIFECYCLE
|
// APP LIFECYCLE
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
// Long-lived SQLite-Handle (Plan 04b+ Voraussetzung). Wird in app.whenReady
|
||||||
|
// geoeffnet, in shutdownCleanup geschlossen. getAppDb() returnt null wenn
|
||||||
|
// Open fehlgeschlagen ist (Native-Build-Probleme) — Caller mussen das pruefen.
|
||||||
|
let appDb: DbHandle | null = null;
|
||||||
|
export function getAppDb(): DbHandle | null { return appDb; }
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
app.setAppUserModelId('com.twitch.vodmanager');
|
app.setAppUserModelId('com.twitch.vodmanager');
|
||||||
refreshBundledToolPaths(true);
|
refreshBundledToolPaths(true);
|
||||||
startMetadataCacheCleanup();
|
startMetadataCacheCleanup();
|
||||||
startDebugLogFlushTimer();
|
startDebugLogFlushTimer();
|
||||||
|
|
||||||
// SQLite-Shadow-Migration (Plan 02 / v5.0.0-alpha.1). Idempotent + fail-soft —
|
// SQLite-Open + Shadow-Migration. Long-lived handle in appDb (siehe oben).
|
||||||
// bei Fehler bleibt JSON der Master. Lazy require, damit Native-Build-Fehler
|
// Lazy require, damit Native-Build-Fehler den App-Start nicht verhindern.
|
||||||
// den App-Start nicht verhindern.
|
|
||||||
try {
|
try {
|
||||||
const { openDatabase } = require('./main/infra/db');
|
const { openDatabase } = require('./main/infra/db');
|
||||||
const { migrateJsonToSqlite } = require('./main/domain/migrator');
|
const { migrateJsonToSqlite } = require('./main/domain/migrator');
|
||||||
const dbPath = path.join(APPDATA_DIR, 'app.db');
|
const dbPath = path.join(APPDATA_DIR, 'app.db');
|
||||||
const db = openDatabase(dbPath);
|
appDb = openDatabase(dbPath);
|
||||||
try {
|
const result = migrateJsonToSqlite({ db: appDb, appDataDir: APPDATA_DIR });
|
||||||
const result = migrateJsonToSqlite({ db, appDataDir: APPDATA_DIR });
|
appendDebugLog('sqlite-migrator', result);
|
||||||
appendDebugLog('sqlite-migrator', result);
|
|
||||||
} finally {
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
appendDebugLog('sqlite-migrator-failed', {
|
appendDebugLog('sqlite-open-failed', {
|
||||||
error: e instanceof Error ? e.message : String(e),
|
error: e instanceof Error ? e.message : String(e),
|
||||||
});
|
});
|
||||||
|
appDb = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
restartAutoRecordPoller();
|
restartAutoRecordPoller();
|
||||||
@ -7291,6 +7294,13 @@ function shutdownCleanup(reason: 'window-all-closed' | 'before-quit'): void {
|
|||||||
saveConfig(config);
|
saveConfig(config);
|
||||||
flushQueueSave();
|
flushQueueSave();
|
||||||
|
|
||||||
|
// SQLite-Handle schliessen, falls geoeffnet — WAL-Checkpoint passiert beim
|
||||||
|
// close, sodass beim naechsten Start keine .wal/.shm orphans bleiben.
|
||||||
|
if (appDb) {
|
||||||
|
try { appDb.close(); } catch { /* already closed */ }
|
||||||
|
appDb = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Flush debug log AFTER persisting state so any errors saving config /
|
// Flush debug log AFTER persisting state so any errors saving config /
|
||||||
// queue land in the log before the timer is gone.
|
// queue land in the log before the timer is gone.
|
||||||
stopDebugLogFlushTimer(true);
|
stopDebugLogFlushTimer(true);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user