Fix WS deadlock: never block on perm_rx in the chat handler
Since story 884 the Matrix permission listener (and the sled uplink, when configured) hold services.perm_rx for the process lifetime. The WS chat handler's blocking `lock().await` on that same mutex therefore parked the entire WS connection loop forever on StartChat: chat_fut was never polled, RPC frames on the socket were never answered, and everything queued behind the dispatcher's serial session lock — wedging /mcp and /rpc while /health stayed green. Use try_lock instead: if another task already owns permission routing, run the chat without the local permission-forwarding select arm (a pending future keeps the select shape unchanged). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019fHdm92yjvguPi2LiXfLB9
This commit is contained in:
@@ -147,13 +147,34 @@ pub async fn ws_handler(ws: WebSocket, ctx: Data<&Arc<AppContext>>) -> impl poem
|
||||
);
|
||||
tokio::pin!(chat_fut);
|
||||
|
||||
let mut perm_rx = ctx.services.perm_rx.lock().await;
|
||||
// Take perm_rx for local permission forwarding — but never
|
||||
// block on it. Since story 884 the Matrix permission
|
||||
// listener (and the sled uplink, when configured) hold this
|
||||
// lock for the process lifetime, so a blocking
|
||||
// `lock().await` here parks the entire WS connection loop
|
||||
// forever: chat_fut is never polled, RPC frames on this
|
||||
// socket are never answered, and everything queues behind
|
||||
// the dispatcher's serial session lock. If another task
|
||||
// already owns permission routing, proceed without the
|
||||
// local forwarding arm — requests are handled there.
|
||||
let mut perm_rx = ctx.services.perm_rx.try_lock().ok();
|
||||
if perm_rx.is_none() {
|
||||
crate::slog!(
|
||||
"[ws] perm_rx held by another listener; \
|
||||
skipping local permission forwarding for this chat"
|
||||
);
|
||||
}
|
||||
|
||||
let chat_result = loop {
|
||||
tokio::select! {
|
||||
result = &mut chat_fut => break result,
|
||||
|
||||
Some(perm_fwd) = perm_rx.recv() => {
|
||||
Some(perm_fwd) = async {
|
||||
match perm_rx.as_mut() {
|
||||
Some(rx) => rx.recv().await,
|
||||
None => std::future::pending().await,
|
||||
}
|
||||
} => {
|
||||
let _ = tx.send(ws::permission_request_response(
|
||||
&perm_fwd.request_id,
|
||||
&perm_fwd.tool_name,
|
||||
|
||||
Reference in New Issue
Block a user