热键 bridge 串行阻塞:一次慢 IO 就能让热键彻底失灵(已为此挖了三条旁路)
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 12/100
- Loại issue
- Tái cấu trúc
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Ít trao đổi
- Lĩnh vực
- desktop, performance
Hướng nghiên cứu
Read hotkey_bridge_loop and the async_runtime::block_on work it drives, then the three bypasses it spawned: the Esc channel (#853), the combo-cancel channel (#858), and HOTKEY_QUEUE_GRACE_MS / is_queued_chain_press. Read #468/#475 first, since they explain why Pressed/Released ordering must stay serial, and #871 for the current 5s timeouts. Done means latch/phase transitions still follow physical key order while begin_session / end_session leave the bridge thread, backed by tests that key-edge ordering is unchanged.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
现象
热键的按下 / 松开事件走一条串行 bridge 线程(hotkey_bridge_loop,async_runtime::block_on 逐个处理)。而这条线程上跑的是开麦克风、连 ASR、转写、LLM 润色这些慢活。
结果是:这条线程上任何一次慢 IO,都会让热键在此期间完全失去响应 —— 按下开不了录音,松开也停不了,且没有任何 UI 提示,用户只会认为「热键坏了」。
实测(macOS,StepFun 实时 ASR):连续开会话时一次 WebSocket 建连没有返回,之后热键完全无响应,只能退出 app 重开。日志里 tap 线程仍在正常记录按键,只是没人处理:
07:20:14.201 [hotkey] 触发键与其他键组合按下 —— 撤销本次触发 ← tap 活着
07:20:15.985 [hotkey] 触发键与其他键组合按下 —— 撤销本次触发 ← tap 活着
↑ 但没有任何 [coord] hotkey pressed
sample 确认 openless-hotkey-bridge 停在 __psynch_cvwait(block_on 等 future),主线程与 tap 线程都正常。
#871 给三个供应商的建连补了 5s 超时,把「永远死」降级成「死 5 秒」。但那是止血,不是修复。
这个结构已经反复付出代价
它不是一个假设中的隐患 —— 目前代码里至少有三处逻辑,存在的唯一理由就是绕开这条线程会堵:
-
Esc 取消专用通道(#853)。转写 + 润色在 bridge 线程上同步跑,Esc 若与 Pressed/Released 同队列就只能排在后面,等流程结束才被取出,此时 phase 已回 Idle、cancel 变 no-op —— 用户按 Esc 毫无反应。修法是给 Esc 单开一条
Sender<()>+ 专用消费线程。 -
组合键撤销专用通道(#858)。同一个病:撤销事件排在这次按下自己的
begin_session后面,胶囊要等开麦跑完才消失(实测差 0.8~1s)。又单开一条通道。 -
「排队接力」判定(
HOTKEY_QUEUE_GRACE_MS = 120,is_queued_chain_press)。转写期间的按下被缓在 channel 里,会话收尾后才取出;需要额外逻辑区分「刚才排队的那次按下」和「用户新按的」,以免与 #545 的冷却保护打架。
每加一条旁路,就多一组「两条通道之间谁先谁后」的竞态要考虑。#858 里已经为此加了回归测试(Released 抢先跑完时撤销仍须生效)。这是在给同一个病贴第 N 张膏药。
为什么不能简单地把串行撤掉
串行本身是 #468/#475 的解药:Pressed/Released 若并行执行,hotkey_trigger_held latch 的翻转顺序会乱(Windows 的 WH_KEYBOARD_LL 边沿间隔可到微秒级),表现为「录音停不下来」或「下次按键被静默吞掉」。代码注释里标为 P0。
所以这不是「删掉 block_on 就好」,而是要换一种方式同时满足:
- 按键边沿的处理顺序必须严格跟随物理顺序;
- 慢 IO(开麦 / 建连 / 转写 / 润色)不得占住边沿处理。
候选方向(列出来,不替维护者选)
- A. 边沿处理与会话工作分离:bridge 只做纯同步的状态机迁移(latch、phase 判定),把
begin_session/end_session派发到运行时,用 session id + 代次号丢弃过期结果。顺序由 bridge 保证,慢活不再占线程。 - B. 保留串行,但给所有落在 bridge 上的 await 强制上限:本质是 #871 的推广,简单但治标;只要有人漏加一个超时就会复发。
- C. 单一事件队列 + 优先级:把 Esc / 组合键撤销那些旁路收回同一条队列,用优先级而非独立通道,减少竞态面。不解决「慢活占线程」,但能止住旁路增殖。
各有代价,且都动到当初为修 #468/#475 而引入的部分,风险不低。
我的打算
暂不动手,等维护者定方向。这块是全仓库最容易出竞态的地方,我不想在方向未定时先改,那只会制造一处最难合并的分叉。
如果维护者认可某条路子,我可以按那个方向做,并先把按键顺序那部分单独抽出来补测试,确认改完顺序仍然正确再动线程。
相关:#853、#858、#871(均为绕开或止血),#468 / #475(串行的由来),#545(冷却保护,与排队接力互相牵扯)。
- Ngôn ngữ chính
- Rust
- Star
- 3.7k
- Fork
- 349
- Merge trung bình
- 2 ngày 14 giờ
- Pull request đã merge (30 ngày)
- 97
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của Open-Less/openless
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[windows] 录音快捷键还不支持设置为ScrllLock键Có thể đã có người làm @HKLHaoBin đã nhận 9 ngày trước. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Open-Less/openless#1241 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 18/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[omni] 多模态模式开启翻译后,译文时有时无,或混在 JSON 字段里Có thể đã có người làm @Breadswim đã nhận 2 ngày trước. Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 52/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[omni] 多模态「验证」对 OpenAI gpt-audio-1.5 必然返回 400Có thể đã có người làm @Breadswim đã nhận 2 ngày trước. Đang mở
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 58/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của Open-Less/openless
Issue tương tự
-
priority: low ☕️ type: bug 🐛
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area:docs documentation good first issue priority:medium
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
rtk-ai/rtk#4958 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
feature
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
calagopus/panel#285 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
agent-self
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
yologdev/yoyo-evolve#1117 · 1 bình luận ·
-
[Bug]: streamed Responses API flex_unavailable error maps to 500 InternalServerError instead of 429Đang mởllm translation
Độ khó 2/5 Dưới một giờ Mức phù hợp với người mới 85/100
BerriAI/litellm#49736 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày