hive-agent: extract turn-error recovery to fix clippy too_many_lines on handle_turn

This commit is contained in:
damocles 2026-08-02 02:03:21 +02:00
commit 77e30dd1bc

View file

@ -810,6 +810,52 @@ async fn handle_turn<S: Surface>(
if outcome.is_ok() {
S::ack_turn(socket).await;
}
handle_turn_error_recovery::<S>(&outcome, bus, socket).await;
if let Some(stats) = stats {
// Fresh session this turn → mint a `sessions` row and set its id on
// the bus so this turn (and subsequent ones until the next fresh
// start) stamp `turn_stats.session_id`. Takes the one-shot flag
// `run_claude` set when it suppressed `--continue`.
if bus.take_fresh_session() {
let sid = stats.start_session(started_at, &model_at_start);
bus.set_session_id(sid);
}
let ended_at = chrono::Utc::now().timestamp();
let duration_ms = i64::try_from(started_instant.elapsed().as_millis()).unwrap_or(i64::MAX);
let (open_threads, open_reminders) = S::post_turn_counts(socket).await;
let row = serve_common::build_row(serve_common::TurnRowArgs {
started_at,
ended_at,
duration_ms,
model: model_at_start,
wake_from: from.clone(),
outcome: &outcome,
bus,
open_threads_count: open_threads,
open_reminders_count: open_reminders,
});
stats.record(&row);
}
let pending = S::inbox_unread(socket).await;
if pending > 0 {
tracing::info!(%pending, "pending messages after turn; fetching next");
}
TurnControl {
auth_failed: matches!(outcome, Err(turn::TurnError::AuthFailed)),
}
}
/// The non-happy-path half of `handle_turn`: react to each `TurnError`
/// variant the turn could have failed with (park-and-retry on rate-limit/
/// stall/auth, requeue-for-a-fresh-turn on prompt-too-long/session-not-
/// found, notify the parent on a hard failure). Split out purely to keep
/// `handle_turn` itself under clippy's line-count lint — no behavior
/// change from when this lived inline.
async fn handle_turn_error_recovery<S: Surface>(
outcome: &turn::TurnOutcome,
bus: &Bus,
socket: &Path,
) {
if matches!(outcome, Err(turn::TurnError::RateLimited)) {
let secs = turn::rate_limit_sleep_secs();
bus.emit_status("rate_limited");
@ -860,39 +906,7 @@ async fn handle_turn<S: Surface>(
tracing::warn!("session-not-found; requeueing message for a fresh turn");
S::requeue_inflight(socket).await;
}
if let Err(turn::TurnError::Failed(e)) = &outcome {
if let Err(turn::TurnError::Failed(e)) = outcome {
S::send_to_parent(socket, format_turn_failure(e)).await;
}
if let Some(stats) = stats {
// Fresh session this turn → mint a `sessions` row and set its id on
// the bus so this turn (and subsequent ones until the next fresh
// start) stamp `turn_stats.session_id`. Takes the one-shot flag
// `run_claude` set when it suppressed `--continue`.
if bus.take_fresh_session() {
let sid = stats.start_session(started_at, &model_at_start);
bus.set_session_id(sid);
}
let ended_at = chrono::Utc::now().timestamp();
let duration_ms = i64::try_from(started_instant.elapsed().as_millis()).unwrap_or(i64::MAX);
let (open_threads, open_reminders) = S::post_turn_counts(socket).await;
let row = serve_common::build_row(serve_common::TurnRowArgs {
started_at,
ended_at,
duration_ms,
model: model_at_start,
wake_from: from.clone(),
outcome: &outcome,
bus,
open_threads_count: open_threads,
open_reminders_count: open_reminders,
});
stats.record(&row);
}
let pending = S::inbox_unread(socket).await;
if pending > 0 {
tracing::info!(%pending, "pending messages after turn; fetching next");
}
TurnControl {
auth_failed: matches!(outcome, Err(turn::TurnError::AuthFailed)),
}
}