fix: 数据库初始化加固 — 关闭流程禁止重开 + initDb 串行化 + 错误详情显示

- closeDatabase 后置 isClosing 标记,关闭流程中 getDb 直接拒绝,
  避免 forceClose 前其他组件重新建立连接(未关闭即被进程终止)
- initDb 串行链:失败重置后并发 getDb 不再同时 createDatabase
- 弹框显示 ARIA_OPEN_ERROR 等包装错误的 details(原始异常信息)
This commit is contained in:
thzxx
2026-08-09 21:09:15 +08:00
parent 8bee37cb89
commit 63fa0d3040
+23 -4
View File
@@ -90,6 +90,11 @@ const ACTIVE_TAB_COLUMNS: Record<string, ColumnDef> = {
let dbPromise: Promise<MetonaSqlark> | 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<unknown> = Promise.resolve()
const RESET_PENDING_KEY = 'marklite-db-reset-pending'
// AriaEngine 的 IndexedDBBackend 内部库名 = `aria-${name}`sqlark 源码约定)
@@ -172,10 +177,11 @@ async function initDb(): Promise<MetonaSqlark> {
}
/**
* v0.6.0: 关闭数据库 — 应用退出前调用,确保 WAL/SSTable 干净落盘,
* v0.6.1: 关闭数据库 — 应用退出前调用,确保 WAL/SSTable 干净落盘,
* 避免渲染进程被销毁时 flush 中断留下半写文件导致下次启动损坏。
*/
export async function closeDatabase(): Promise<void> {
isClosing = true
const current = dbPromise
dbPromise = null
if (!current) return
@@ -189,16 +195,29 @@ export async function closeDatabase(): Promise<void> {
export function getDb(): Promise<MetonaSqlark> {
if (!dbPromise) {
dbPromise = initDb().catch(err => {
// v0.6.0: 初始化失败不再静默 — 记录日志并提示用户(否则所有数据持久化静默失效
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}`)
MeToast?.error(`数据库初始化失败(${code}):${msg}${detailText}`)
}, 0)
} catch {
/* 提示失败不影响主流程 */