Dealing with bot failures
This commit is contained in:
@@ -210,6 +210,17 @@ pub(in crate::chat::transport::matrix::bot) async fn handle_message(
|
|||||||
|
|
||||||
// Persist to disk so history survives server restarts.
|
// Persist to disk so history survives server restarts.
|
||||||
save_history(&ctx.services.project_root, &guard);
|
save_history(&ctx.services.project_root, &guard);
|
||||||
|
} else {
|
||||||
|
// Clear session_id on error so a poisoned session (e.g. pending
|
||||||
|
// tool call with no response) doesn't cause a crash loop on resume.
|
||||||
|
let mut guard = ctx.history.lock().await;
|
||||||
|
if let Some(conv) = guard.get_mut(&room_id)
|
||||||
|
&& conv.session_id.is_some()
|
||||||
|
{
|
||||||
|
slog!("[matrix-bot] clearing session_id after error to prevent crash loop");
|
||||||
|
conv.session_id = None;
|
||||||
|
save_history(&ctx.services.project_root, &guard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -371,23 +371,38 @@ fn run_pty_session(
|
|||||||
// Wait briefly for Claude Code to flush its session transcript to disk.
|
// Wait briefly for Claude Code to flush its session transcript to disk.
|
||||||
// The `result` event means the API response is done, but the process
|
// The `result` event means the API response is done, but the process
|
||||||
// still needs to write the conversation to the JSONL session file.
|
// still needs to write the conversation to the JSONL session file.
|
||||||
match child.try_wait() {
|
let exit_status = match child.try_wait() {
|
||||||
Ok(Some(_)) => {} // Already exited
|
Ok(Some(status)) => Some(status),
|
||||||
_ => {
|
_ => {
|
||||||
// Give it up to 2 seconds to exit cleanly
|
let mut status = None;
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
if let Ok(Some(_)) = child.try_wait() {
|
if let Ok(Some(s)) = child.try_wait() {
|
||||||
|
status = Some(s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If still running after 2s, kill it
|
if status.is_none() {
|
||||||
let _ = child.kill();
|
let _ = child.kill();
|
||||||
let _ = child.wait();
|
status = child.wait().ok();
|
||||||
}
|
}
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
};
|
||||||
// Wait for the reader thread to release the cloned PTY master fd.
|
// Wait for the reader thread to release the cloned PTY master fd.
|
||||||
let _ = reader_handle.join();
|
let _ = reader_handle.join();
|
||||||
|
|
||||||
|
// Non-zero exit without a result event means Claude Code crashed
|
||||||
|
// (e.g. MCP server not yet connected). Propagate as an error so
|
||||||
|
// the caller can clear the session_id instead of persisting it.
|
||||||
|
if !got_result
|
||||||
|
&& let Some(ref status) = exit_status
|
||||||
|
&& !status.success()
|
||||||
|
{
|
||||||
|
slog!("[pty-debug] Claude Code exited with non-zero status: {status}");
|
||||||
|
return Err(format!("Claude Code crashed (exit status: {status})"));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user