Hmbown / Hmbown/Codewhale

v0.9.14: Replace runtime polling loops and blocking shapes with watch/notify

Open
#6,211 1 comment 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Rust
Stars
41k
Forks
3.6k
Avg merge
13h 59m
Merged PRs (30d)
299

Description

From `codewhale-ops/PERF-OPPORTUNITIES-20260915.md` §2 (R3, R4, R7, R8) — mostly **[S]** findings; read the call path before slicing. Each is an independently shippable fix.

## Polling loops that should be watchers/notifications

- [ ] **R3** — `tui/src/tools/workflow/mod.rs:4811–4852`: the completion already arrived on the channel, then `for _ in 0..50 { read-lock; sleep(20ms) }` waits for the manager record to settle — up to 1s added latency per workflow task completion and 50 lock round-trips under fan-out. Carry the terminal status in the completion envelope (it exists in the `completion.payload` path) or subscribe via a per-agent `tokio::sync::watch`.
- [ ] **R7a** — `tui/src/mcp.rs:1534`: per *pending* MCP connection, a 50ms loop doing directory-permission checks + fd-lock open + JSON state load (sync fs at 20Hz per plugin server). One shared fs-notify watcher task.
- [ ] **R7b** — `tui/src/runtime_api.rs:2126`: each fleet SSE viewer polls the event store at 250ms. `tokio::sync::watch`/`broadcast` fed by the append path; poll only as fallback.
- [ ] **R7c** — `tui/src/task_manager.rs:2876`: 5ms retry loop for the store file lock = 200 wakeups/s under contention. Exponential backoff 5→50ms plus an in-process `tokio::sync::Mutex` for same-process contenders.

## Blocking / serialization shapes

- [ ] **R4** — `crates/mcp/src/stdio_client.rs:964–991`: `Drop for Connection` runs `try_wait` + `thread::sleep(10ms)` up to a 500ms deadline on whichever thread drops it (manager reload, pool rebuild stalls an executor thread). `Connection` is also behind `std::sync::Mutex`, so one in-flight request blocks all callers of that server. Shutdown in a reaper task / `spawn_blocking`; longer term replace with `tokio::process` so the wait is event-driven.
- [ ] **R8a** — `tui/src/exec_agent.rs:543`: `rx_event.write().await` guard held across `recv().await` excludes recovery readers until the next event arrives. `Notify` or a dedicated single-owner consumer task. Same shape at `runtime_threads.rs:183` (deadline-bounded there).
- [ ] **R8b** — `app-server/src/lib.rs:620,2403`: sequential `interrupt_stdio_turn` in a loop at teardown — `join_all` them.

Reusable idiom: `tokio::sync::watch` for "latest state" instead of polling; `Notify` for one-shot wakeups. Every 5ms/20ms/50ms/250ms loop above is a watch channel waiting to happen.

Contributor guide

Open the contributing guide

Research direction

Read the listed call paths in tui/src/tools/workflow/mod.rs, tui/src/mcp.rs, tui/src/runtime_api.rs, tui/src/task_manager.rs, crates/mcp/src/stdio_client.rs, tui/src/exec_agent.rs, runtime_threads.rs, and app-server/src/lib.rs before selecting one independently shippable item. Trace each polling or blocking path and its existing channel or append path, then verify the selected change removes the described wait or serialization shape without changing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, cli, tooling
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.