fix(database): improve web environment database connection handling
- Add pre-open check for web to release potentially stale OPFS handles - Unify close logic across platforms instead of skipping for web - Add proper logging for connection lifecycle operations - Remove obsolete error check for "cannot create file" during retries
This commit is contained in:
@@ -53,6 +53,17 @@ async function withMutex<T>(fn: () => Promise<T>): Promise<T> {
|
|||||||
async function openDatabaseWithRetry(dbName: string, maxRetries: number = 3): Promise<SQLite.SQLiteDatabase> {
|
async function openDatabaseWithRetry(dbName: string, maxRetries: number = 3): Promise<SQLite.SQLiteDatabase> {
|
||||||
const isWeb = typeof window !== 'undefined';
|
const isWeb = typeof window !== 'undefined';
|
||||||
|
|
||||||
|
if (isWeb) {
|
||||||
|
try {
|
||||||
|
const tempDb = await SQLite.openDatabaseAsync(dbName);
|
||||||
|
await tempDb.closeAsync();
|
||||||
|
console.log('[Database] Web: 预打开成功,已释放可能残留的句柄');
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[Database] Web: 预打开失败:', String(e));
|
||||||
|
}
|
||||||
|
await new Promise(r => setTimeout(r, 50));
|
||||||
|
}
|
||||||
|
|
||||||
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
||||||
try {
|
try {
|
||||||
const database = await SQLite.openDatabaseAsync(dbName);
|
const database = await SQLite.openDatabaseAsync(dbName);
|
||||||
@@ -66,7 +77,7 @@ async function openDatabaseWithRetry(dbName: string, maxRetries: number = 3): Pr
|
|||||||
console.warn(`[Database] ${delay}ms 后重试...`);
|
console.warn(`[Database] ${delay}ms 后重试...`);
|
||||||
await new Promise(r => setTimeout(r, delay));
|
await new Promise(r => setTimeout(r, delay));
|
||||||
|
|
||||||
if (msg.includes('Invalid VFS state') || msg.includes('cannot create file')) {
|
if (msg.includes('Invalid VFS state')) {
|
||||||
try {
|
try {
|
||||||
await SQLite.deleteDatabaseAsync(dbName);
|
await SQLite.deleteDatabaseAsync(dbName);
|
||||||
console.warn('[Database] 已删除损坏的数据库文件');
|
console.warn('[Database] 已删除损坏的数据库文件');
|
||||||
@@ -237,20 +248,19 @@ export const initDatabase = async (userId?: string): Promise<void> => {
|
|||||||
const isWeb = typeof window !== 'undefined';
|
const isWeb = typeof window !== 'undefined';
|
||||||
|
|
||||||
if (db) {
|
if (db) {
|
||||||
if (isWeb) {
|
console.log(`[Database ${mutexId}] 关闭旧数据库连接...`);
|
||||||
console.log(`[Database ${mutexId}] Web:切换用户,直接置空旧连接`);
|
|
||||||
db = null;
|
|
||||||
currentDbUserId = null;
|
|
||||||
isInitialized = false;
|
|
||||||
} else {
|
|
||||||
try {
|
try {
|
||||||
await db.closeAsync();
|
await db.closeAsync();
|
||||||
|
console.log(`[Database ${mutexId}] 旧连接已关闭`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(`[Database ${mutexId}] 关闭旧连接失败:`, e);
|
console.warn(`[Database ${mutexId}] 关闭旧连接失败:`, e);
|
||||||
}
|
}
|
||||||
db = null;
|
db = null;
|
||||||
currentDbUserId = null;
|
currentDbUserId = null;
|
||||||
isInitialized = false;
|
isInitialized = false;
|
||||||
|
|
||||||
|
if (isWeb) {
|
||||||
|
await new Promise(r => setTimeout(r, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,17 +295,9 @@ export const closeDatabase = async (): Promise<void> => {
|
|||||||
await withMutex(async () => {
|
await withMutex(async () => {
|
||||||
if (!db) return;
|
if (!db) return;
|
||||||
|
|
||||||
const isWeb = typeof window !== 'undefined';
|
|
||||||
if (isWeb) {
|
|
||||||
console.log('[Database] Web 环境:跳过关闭数据库,避免 OPFS 句柄冲突');
|
|
||||||
db = null;
|
|
||||||
currentDbUserId = null;
|
|
||||||
isInitialized = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.closeAsync();
|
await db.closeAsync();
|
||||||
|
console.log('[Database] 数据库已关闭');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('[Database] 关闭失败:', e);
|
console.warn('[Database] 关闭失败:', e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user