dailyuse本地登录流程和powersync同步问题
dailyuse 本地登录恢复、认证状态同步与 PowerSync 初始化竞态问题的排障记录
#tech / dev / desktop
#resource / electron
#type / debug
#status / growing
[!info] related notes
dailyuse本地登录流程和powersync同步问题
问题
TL;DR: 系统审查发现了 6 个相互关联的 bug,导致个人中心 “Authentication required” 错误、PowerSync 连接失败和 identityId 问题。核心原因是:sessionId 不一致、main 进程与 renderer 认证状态不同步、PowerSync 重复/竞态初始化。
Phase 1: 修复关键认证状态 Bug
Step 1: 修复 login 流程中 sessionId 不匹配
- 文件: AuthDesktopApplicationService.ts:290-310
- 问题: onSuccess 回调中 response.session.id || crypto.randomUUID() 分别被执行了两次 — 一次给 tokenManager.saveTokens(),一次给 sessionManager.createOnlineSession()。当 API 未返回 session.id 时,两次调用生成不同的 UUID,导致 token 存储的 sessionId (X) 与数据库存储的 session (Y) 不一致。重启后 restoreSession() 查找 X 但找不到,返回 needsReLogin: true
- 修复: 将 sessionId 提取到单独的 const sessionId = response.session.id || crypto.randomUUID() 变量,两处都使用同一个值
Step 2: 添加 renderer 启动时的认证状态同步
- 文件: authenticationStore.ts, renderer main.ts
- 问题: Renderer 依赖 Pinia 持久化 (localStorage)。如果 main 进程会话丢失(过期、数据库损坏),但 localStorage 仍存有旧 token,renderer 显示 isAuthenticated = true 但所有 withAuth() IPC 调用都返回 AUTH_REQUIRED
- 修复: renderer 启动时(路由导航前),调用 auth:get-status IPC 验证 main 进程认证状态。若不一致则:调用 auth:initialize 尝试恢复,若仍失败则清除 store 并跳转登录
Step 3: 非 auto-login 流程添加 auth:initialize 调用
- 文件: renderer 初始化阶段
- 问题: 当 autoLogin 禁用时,main 进程从不调用 AuthDesktopApplicationService.initialize(),isInitialized 一直为 false
- 修复: main window renderer 加载后,在初始化阶段调用 auth:initialize IPC,确保 main 进程会话状态在任何 withAuth() 调用前已恢复
Phase 2: 修复 PowerSync 初始化问题
Step 4: 移除 app-lifecycle.ts 中重复的 PowerSync 初始化
- 文件: app-lifecycle.ts:165-180
- 问题: auto-login 后, AuthDesktopApplicationService.initialize()(通过 setImmediate 的 initializePowerSyncAsync())和 app-lifecycle.ts(直接调用 connectPowerSync())都尝试连接 PowerSync,两者竞态检查
if (powerSyncDb)都看到 null,各自创建独立的 PowerSyncDatabase 实例 - 修复: 从 app-lifecycle.ts 移除直接的 connectPowerSync() / openPowerSyncLocalOnly() 调用,让 AuthDesktopApplicationService 成为 PowerSync 生命周期的唯一控制者
Step 5: 为 connectPowerSync() 添加并发保护
- 文件: powersync.ts:158-179
- 问题: connectPowerSync() 没有互斥锁,并发调用会创建多个数据库实例
- 修复: 添加
connectingPromise变量存储进行中的连接 Promise,第二次调用复用已有 Promise。openPowerSyncLocalOnly() 同理
Step 6: 将 PowerSync 初始化从 setImmediate 改为可追踪的 Promise
- 文件: AuthDesktopApplicationService.ts:1043-1058
- 问题: setImmediate() 延迟 PowerSync 连接,无法追踪成功/失败,造成时序问题
- 修复: 改为存储 Promise 引用(
this.powerSyncPromise),保持非阻塞但可追踪
Verification
- 登录 → 导航到个人中心 → 验证无 AUTH_REQUIRED 错误
- 登录 → 关闭应用 → 重启 → 验证 auto-login 恢复会话 → 个人中心正常
- 登录(rememberPassword) → 断网 → 重启 → 离线登录 → 个人中心正常
- 登录 → 验证 PowerSync 日志显示 “Connected” → 无重复连接日志 → 数据同步正常
- 注册 → 验证个人中心正常 → 验证 PowerSync 连接
- 快速导航多个需认证页面 → 无 AUTH_REQUIRED 错误