Skip to content

perf(coordinator): 可选热键 supervisor 注册成功即退出,消除稳态轮询#671

Merged
appergb merged 1 commit into
betafrom
fix/470-hotkey-supervisor-exit
Jun 16, 2026
Merged

perf(coordinator): 可选热键 supervisor 注册成功即退出,消除稳态轮询#671
appergb merged 1 commit into
betafrom
fix/470-hotkey-supervisor-exit

Conversation

@appergb

@appergb appergb commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

User description

源自 #470 Cloud 性能审查 #2。combo/translation/action 三类可选热键 supervisor 原本注册成功后不退出,稳态每 5s 醒来读 prefs,多线程常驻空转。

改动:对齐主 hotkey_supervisor_loop 的 exit-on-success 模式——到达「已安装」或「已主动停用」稳态即 return 退出,零稳态轮询。仅改控制流(sleep+continuereturn),无新增锁。

安全前提(已逐函数确认):用户启用/改/停这些热键时 set_*_hotkey 命令与 persist_settings diff 都会调 update_*_hotkey_binding,其覆盖「monitor 为 None → 从零 start+spawn」安装路径 → 退出后启停改键无需重启即时生效;ComboHotkeyMonitor 注册后驻留、无运行中自注销 → monitor 不会自己死,无需守护。有界路径(失败重试 3s / recv_timeout 5s / app未就绪 1s)全部保留。

验证:macOS cargo check 通过 + 对抗式复审 pass。Windows/Linux cfg 分支靠 CI(控制流三端等价,无 cfg 分歧)。


PR Type

Enhancement


Description

  • 消除 combo/translation/action 可选热键 supervisor 的稳态轮询

  • 对齐主 supervisor 的 exit-on-success 模式:注册成功即 return 退出

  • 依赖 update_*_hotkey_binding 主动路径确保启停即时生效,无需守护


Diagram Walkthrough

flowchart LR
  Before("之前") --> Loop("loop {}") --> Check1["检查 prefs"] --> Decision1{"已安装/已禁用?"}
  Decision1 -->|是| Uninstall["卸载热键"] --> Sleep["sleep 5s"] --> Loop
  Decision1 -->|否| Decision2{"Monitor 已存在?"}
  Decision2 -->|是| Sleep
  Decision2 -->|否| Install["安装热键"] --> ReturnBefore["保持 loop"]
  After("之后") --> Loop2["loop {}"] --> Check2["检查 prefs"] --> Decision3{"已安装/已禁用?"}
  Decision3 -->|是| Uninstall2["卸载热键"] --> ReturnAfter1["return"]
  Decision3 -->|否| Decision4{"Monitor 已存在?"}
  Decision4 -->|是| ReturnAfter2["return"]
  Decision4 -->|否| Install2["安装热键"] --> ReturnAfter3["return"]
Loading

File Walkthrough

Relevant files
Enhancement
coordinator.rs
supervisor loop exit-on-success                                                   

openless-all/app/src-tauri/src/coordinator.rs

  • 在 combo_hotkey_supervisor_loop 中将三个稳定状态分支从 sleep+continue 改为 return
  • 在 translation_hotkey_supervisor_loop 中将两个稳定状态分支改为 return
  • 在 action_hotkey_supervisor_loop 中将三个稳定状态分支改为 return
  • 添加注释说明对齐主 supervisor 的 exit-on-success 模式,依赖 update_*_hotkey_binding
    主动路径
+18/-18 

issue #470:combo/translation/action 三类可选热键 supervisor 原本注册成功后不退出,稳态
每 5s 醒来读 prefs,多线程常驻空转。改为对齐主 hotkey_supervisor_loop 的 exit-on-success
模式——到达「已安装」或「已主动停用」稳态即 return 退出,零轮询。

安全前提(已逐函数确认):用户启用/改/停这些热键时,set_*_hotkey 命令与 persist_settings
diff 都会调 update_*_hotkey_binding,其覆盖「monitor 为 None → 从零 start+spawn」安装路径,
故退出后启停改键无需重启即时生效;ComboHotkeyMonitor 注册后驻留、无运行中自注销,monitor
不会自己死,无需 supervisor 守护。失败重试 sleep(3s)/recv_timeout(5s)/app未就绪 sleep(1s)
等有界路径全部保留。
@github-actions

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

2 - Partially compliant

Compliant requirements:

(empty)

Non-compliant requirements:

  • Add hold-to-talk hotkey mode alongside existing toggle mode
  • Emit .pressed/.released events in OpenLessHotkey
  • Update DictationCoordinator to interpret events per HotkeyMode
  • Add settings UI segmented picker for recording mode
  • Bump build version to 1.0.01/A1003

Requires further human verification:

(empty)

470 - Partially compliant

Compliant requirements:

(empty)

Non-compliant requirements:

  • Fix missing recording capsule (录音胶囊) on Windows when voice input is active
  • Ensure visual UI hint appears on desktop
  • Fix basic bug on Windows platform (P1)

Requires further human verification:

(empty)

⏱️ Estimated effort to review: 1 🔵⚪⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@appergb

appergb commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator Author

@claude 请审查本 PR(#470 #2:可选热键 supervisor 改 exit-on-success)。这是并发核心,重点核查:改成 return 的每处是否确为稳态(已安装/已停用)而非有界重试路径;退出后用户启用未配置热键时 update_*_binding 是否真从零安装 monitor(否则启用需重启的回归);有无引入竞态。

@claude

claude Bot commented Jun 15, 2026

Copy link
Copy Markdown

Claude finished @appergb's task in 2m 53s —— View job


PR #671 审查:可选热键 supervisor exit-on-success

  • 读取 coordinator.rs 相关代码
  • 核查每处 return 是否确为稳态而非有界重试路径
  • 核查 update_*_hotkey_binding 是否真从零安装 monitor
  • 检查竞态条件

结论:逻辑正确,可合并

三个核心问题全部通过。详细分析如下。


1. return 处是否确为稳态(非有界重试路径)✅

逐函数确认,所有 return 都在已完成动作的稳态分支,有界重试路径(recv_timeout 超时、init_result Err)一律保留为 sleep+continue

combo_hotkey_supervisor_loop(L2136–2218)

分支 条件 处理 是稳态?
legacy_modifier_trigger is Some 非 Custom 绑定 take_combo_hotkeyreturn ✅ 已卸载,主动路径管理
is_unconfigured_shortcut 无有效主键 take_combo_hotkeyreturn ✅ 已卸载
combo_hotkey.lock().is_some() monitor 已装 return ✅ 已安装稳态
recv_timeout Err 主线程未回执 sleep 3s; continue ✅ 保留重试
init_result Err 注册失败 sleep 3s; continue ✅ 保留重试
app.lock().is_none() app 未就绪 sleep 1s; continue ✅ 保留重试

translation_hotkey_supervisor_loopaction_hotkey_supervisor_loop 同样模式,所有有界路径未改动。


2. update_*_binding 从零安装 monitor ✅

用户启用未配置热键时,update_*_binding 的 None 路径覆盖完整:

update_combo_hotkey_binding(L767–816)

// 在 run_on_main_thread 内:
if let Some(monitor) = inner_clone.combo_hotkey.lock().as_ref() {
    monitor.update_binding(...);  // 已有:换绑
    return;
}
// None 路径:
ComboHotkeyMonitor::start(binding, tx)  // 从零安装
*inner_clone.combo_hotkey.lock() = Some(monitor);
spawn(combo_hotkey_bridge_loop)         // 连同 bridge 一并起

update_translation_hotkey_on_main_thread(L2314 附近):同样模式,None 时从零 ComboHotkeyMonitor::start + spawn bridge。

update_action_hotkey_binding(L933–972):同样模式,None 时从零 ComboHotkeyMonitor::start + spawn bridge。

三者均无遗漏。用户启用 → set_*_hotkeyupdate_*_binding → monitor None → 从零安装 → 立即生效,无需重启


3. 竞态检查 ✅(无新增)

supervisor 与 update_*_binding 并发安装(TOCTOU):

理论路径:supervisor 检查 combo_hotkey.lock().is_none() 后、调用 run_on_main_thread 之前,update_combo_hotkey_bindingrun_on_main_thread 先执行完装上 monitor_A;supervisor 的闭包随后在主线程执行,装上 monitor_B 覆盖 monitor_A,bridge_A 的 channel sender 被 drop,bridge_A 会在下一次 rx.recv() 收到 Err干净退出

此竞态在 PR 前同样存在(run_on_main_thread 是顺序队列,两次调用的闭包仍可交错注册),本次改动不引入新窗口,也不改变结果:最后写入者胜出,孤立 bridge 干净退出。

monitor 生命期take_combo_hotkey_on_main_thread 在主线程 drop monitor → tx 被 drop → bridge rx.recv() 返回 Err → bridge 退出,无泄漏。

exit-on-success 后的重装链:supervisor 退出 → 用户改键 → update_combo_hotkey_binding take + reinstall,全程无需 supervisor 守护,链路完整。


细节观察(非阻塞)

translation_hotkey_supervisor_loop 的 builtin/modifier 分支在退出前直接调用:

monitor.update_modifier_shortcuts(qa_trigger, translation_trigger);

try_update_translation_hotkey_bindingself.update_modifier_shortcut_bindings(),两者语义等价,无差异。


总结

改动纯控制流,稳态识别准确,从零安装路径完整,无新增竞态,有界重试路径全部保留。

@appergb appergb merged commit 2d783ce into beta Jun 16, 2026
5 checks passed
@appergb appergb deleted the fix/470-hotkey-supervisor-exit branch June 16, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant