From 63fa0d3040057574d8879a91dde5daa0f3037d23 Mon Sep 17 00:00:00 2001 From: thzxx Date: Sun, 9 Aug 2026 21:09:15 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=95=B0=E6=8D=AE=E5=BA=93=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E5=8A=A0=E5=9B=BA=20=E2=80=94=20=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E6=B5=81=E7=A8=8B=E7=A6=81=E6=AD=A2=E9=87=8D=E5=BC=80?= =?UTF-8?q?=20+=20initDb=20=E4=B8=B2=E8=A1=8C=E5=8C=96=20+=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E8=AF=A6=E6=83=85=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - closeDatabase 后置 isClosing 标记,关闭流程中 getDb 直接拒绝, 避免 forceClose 前其他组件重新建立连接(未关闭即被进程终止) - initDb 串行链:失败重置后并发 getDb 不再同时 createDatabase - 弹框显示 ARIA_OPEN_ERROR 等包装错误的 details(原始异常信息) --- src/renderer/db/schema.ts | 53 ++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/renderer/db/schema.ts b/src/renderer/db/schema.ts index 3faf359..aca95e3 100644 --- a/src/renderer/db/schema.ts +++ b/src/renderer/db/schema.ts @@ -90,6 +90,11 @@ const ACTIVE_TAB_COLUMNS: Record = { let dbPromise: Promise | null = null let initFailedNotified = false let healTriggered = false +// v0.6.1: 关闭流程标记 — closeDatabase 后禁止 getDb 重新打开库, +// 避免 forceClose 前其他组件重新建立连接(未关闭即被进程终止) +let isClosing = false +// v0.6.1: 初始化串行链 — 防止 dbPromise 失败重置后多个 getDb 并发触发 createDatabase +let initChain: Promise = Promise.resolve() const RESET_PENDING_KEY = 'marklite-db-reset-pending' // AriaEngine 的 IndexedDBBackend 内部库名 = `aria-${name}`(sqlark 源码约定) @@ -172,10 +177,11 @@ async function initDb(): Promise { } /** - * v0.6.0: 关闭数据库 — 应用退出前调用,确保 WAL/SSTable 干净落盘, + * v0.6.1: 关闭数据库 — 应用退出前调用,确保 WAL/SSTable 干净落盘, * 避免渲染进程被销毁时 flush 中断留下半写文件导致下次启动损坏。 */ export async function closeDatabase(): Promise { + isClosing = true const current = dbPromise dbPromise = null if (!current) return @@ -189,23 +195,36 @@ export async function closeDatabase(): Promise { export function getDb(): Promise { if (!dbPromise) { - dbPromise = initDb().catch(err => { - // v0.6.0: 初始化失败不再静默 — 记录日志并提示用户(否则所有数据持久化静默失效) - logError('数据库初始化失败', err) - if (!initFailedNotified) { - initFailedNotified = true - try { - const code = (err as { code?: string })?.code ?? 'UNKNOWN' - const msg = err instanceof Error ? err.message : String(err) - setTimeout(() => { - MeToast?.error(`数据库初始化失败(${code}):${msg}`) - }, 0) - } catch { - /* 提示失败不影响主流程 */ - } - } - throw err + if (isClosing) { + // 关闭流程中禁止重开(返回 rejected Promise,调用方 catch 吞掉) + return Promise.reject(new Error('数据库正在关闭')) + } + // 串行化初始化:失败后的重试排队执行,避免并发 createDatabase + initChain = initChain.catch(() => { + /* 前序失败不影响后续 */ }) + dbPromise = initChain + .then(() => initDb()) + .catch(err => { + // v0.6.1: 初始化失败不再静默 — 记录日志并提示用户(否则所有数据持久化静默失效) + logError('数据库初始化失败', err) + if (!initFailedNotified) { + initFailedNotified = true + try { + const code = (err as { code?: string })?.code ?? 'UNKNOWN' + const msg = err instanceof Error ? err.message : String(err) + // ARIA_OPEN_ERROR 等包装错误的具体原因在 details 里(原始异常) + const details = (err as { details?: { message?: string } })?.details?.message + const detailText = details ? ` | 详情: ${details}` : '' + setTimeout(() => { + MeToast?.error(`数据库初始化失败(${code}):${msg}${detailText}`) + }, 0) + } catch { + /* 提示失败不影响主流程 */ + } + } + throw err + }) // 初始化失败时允许下次重试 dbPromise.catch(() => { dbPromise = null