fix: 数据库初始化加固 — 关闭流程禁止重开 + initDb 串行化 + 错误详情显示
- closeDatabase 后置 isClosing 标记,关闭流程中 getDb 直接拒绝, 避免 forceClose 前其他组件重新建立连接(未关闭即被进程终止) - initDb 串行链:失败重置后并发 getDb 不再同时 createDatabase - 弹框显示 ARIA_OPEN_ERROR 等包装错误的 details(原始异常信息)
This commit is contained in:
@@ -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 {
|
||||
/* 提示失败不影响主流程 */
|
||||
|
||||
Reference in New Issue
Block a user