fix(updater): resolve macOS update deadlock (#4206)#4387
Conversation
…progress Remove save_window_state_before_exit and cleanup_before_exit from the macOS/Linux path in install_update_and_restart. These calls run on a tokio worker thread and acquire the window-state plugin lock while querying the main thread for window geometry. When restart_process subsequently triggers ExitRequested(RESTART_EXIT_CODE), the main thread's Exit hook tries to acquire the same lock — causing a permanent mutex deadlock (the app freezes with a spinning cursor and never restarts). This aligns the update path with the DeferToTauriRestart handler in lib.rs, which was already fixed for the same deadlock pattern in farion1231#3998. Additionally: - Wrap updater.check() with tokio::time::timeout(35s) and update.download() with tokio::time::timeout(300s) as defensive guards against network hangs. - Emit "update-download-progress" events during download so the frontend can display real-time download percentage. - Do not use UpdaterBuilder::timeout() to avoid the timeout-leaking- to-download bug documented in tauri-apps/plugins-workspace#2372. Closes farion1231#4206
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bbc2b1150e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // 正确做法与 lib.rs 中 DeferToTauriRestart 路径一致: | ||
| // - 窗口状态:Tauri 的 Exit 钩子在主线程保存(同线程读取几何,无死锁) | ||
| // - 代理/Live 配置:重启后新实例立即接管并恢复代理状态,无需手动清理 |
There was a problem hiding this comment.
Restore exit compensation before direct restart
This path now relies on Tauri Exit hooks/new startup to save state and repair proxy/Live config, but the call immediately after this block is restart_process, whose helper in src-tauri/src/lib.rs documents that it uses tauri::process::restart and bypasses the event loop and plugin RunEvent::Exit hooks. On macOS/Linux updates, users who have proxy takeover active now exit with Live configs still pointing at the old local proxy until the new instance successfully reaches crash recovery (and they stay broken if restart/startup fails), and window geometry is no longer saved on update restarts; either use the Tauri restart path that actually runs those hooks or keep the explicit safe compensation before the direct restart.
Useful? React with 👍 / 👎.
Summary
Fixes the app freeze / permanent hang when clicking "Update" on macOS (Apple Silicon), as reported in #4206.
Root cause:
install_update_and_restartruns on a tokio worker thread. Before restarting, it calledsave_window_state_before_exit, which acquires the window-state plugin lock and queries the main thread for window geometry. Whenrestart_processthen triggersExitRequested(RESTART_EXIT_CODE), the main thread enters the exit event loop and its window-state Exit hook tries to acquire the same lock — mutual deadlock (_pthread_mutex_firstfit_lock_slow/__psynch_mutexwait).Fix: Remove the manual
save_window_state_before_exit/cleanup_before_exitcalls from the macOS/Linux update path, aligning it with theDeferToTauriRestarthandler inlib.rs(which was already corrected for the identical deadlock in #3998):Additional defensive improvements (not the core fix, but prevent related hangs):
updater.check()withtokio::time::timeout(35s)andupdate.download()withtokio::time::timeout(300s)update-download-progressevents during download; frontend shows real-time percentage on the update buttonUpdaterBuilder::timeout()to sidestep the timeout-leaking-to-download bug ([bug][updater] Timeout passed to check() is reused for downloadAndInstall() tauri-apps/plugins-workspace#2372)Related Issue
Closes #4206
Changed Files
src-tauri/src/commands/settings.rssrc/components/settings/AboutSection.tsxTest Plan
pnpm typecheckpassespnpm format:checkpassespnpm test:unitpasses (338/338)cargo clippypasses (Rust toolchain not available in current env — needs CI verification)