fix(runner): propagate duration_ms through SSE done event
The SSE streaming path hardcoded '耗时: -' because duration_ms was never threaded through: - docker.rs: OutputChunk::Done now carries duration_ms, computed from start_container to wait completion via Instant::elapsed - sse.rs: DonePayload gains duration_ms, serialized into the done event - runner.rs: WASM done callback formats the real duration instead of '-' The polling fallback path already had correct duration via ExecResult; only the SSE path was missing it.
This commit is contained in:
parent
aa2d7f3f2d
commit
e50941ef24
@ -31,6 +31,7 @@ struct DonePayload {
|
|||||||
exit_code: Option<i64>,
|
exit_code: Option<i64>,
|
||||||
oom_killed: bool,
|
oom_killed: bool,
|
||||||
timed_out: bool,
|
timed_out: bool,
|
||||||
|
duration_ms: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SSE handler:从 EXEC_STREAMS 取出 receiver(取出即移除,防重复连接),
|
/// SSE handler:从 EXEC_STREAMS 取出 receiver(取出即移除,防重复连接),
|
||||||
@ -52,12 +53,14 @@ pub async fn exec_stream(
|
|||||||
exit_code,
|
exit_code,
|
||||||
oom_killed,
|
oom_killed,
|
||||||
timed_out,
|
timed_out,
|
||||||
|
duration_ms,
|
||||||
} => Event::default()
|
} => Event::default()
|
||||||
.event("done")
|
.event("done")
|
||||||
.json_data(DonePayload {
|
.json_data(DonePayload {
|
||||||
exit_code,
|
exit_code,
|
||||||
oom_killed,
|
oom_killed,
|
||||||
timed_out,
|
timed_out,
|
||||||
|
duration_ms,
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|_| Event::default().event("done").data("{}")),
|
.unwrap_or_else(|_| Event::default().event("done").data("{}")),
|
||||||
})
|
})
|
||||||
|
|||||||
@ -569,6 +569,7 @@ mod sse_consumer {
|
|||||||
exit_code: Option<i64>,
|
exit_code: Option<i64>,
|
||||||
oom_killed: bool,
|
oom_killed: bool,
|
||||||
timed_out: bool,
|
timed_out: bool,
|
||||||
|
duration_ms: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 启动 EventSource 消费 SSE 流。
|
/// 启动 EventSource 消费 SSE 流。
|
||||||
@ -630,17 +631,31 @@ mod sse_consumer {
|
|||||||
exit_code: None,
|
exit_code: None,
|
||||||
oom_killed: false,
|
oom_killed: false,
|
||||||
timed_out: false,
|
timed_out: false,
|
||||||
|
duration_ms: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
let (info, err) = if payload.timed_out {
|
let (info, err) = if payload.timed_out {
|
||||||
("耗时: - · 状态: 超时".to_string(), "超时".to_string())
|
(
|
||||||
|
format!("耗时: {}ms · 状态: 超时", payload.duration_ms),
|
||||||
|
"超时".to_string(),
|
||||||
|
)
|
||||||
} else if payload.oom_killed {
|
} else if payload.oom_killed {
|
||||||
("耗时: - · 状态: 内存超限".to_string(), "内存超限".to_string())
|
(
|
||||||
|
format!("耗时: {}ms · 状态: 内存超限", payload.duration_ms),
|
||||||
|
"内存超限".to_string(),
|
||||||
|
)
|
||||||
} else if payload.exit_code == Some(0) {
|
} else if payload.exit_code == Some(0) {
|
||||||
("耗时: - · 状态: 成功".to_string(), String::new())
|
(
|
||||||
|
format!("耗时: {}ms · 状态: 成功", payload.duration_ms),
|
||||||
|
String::new(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
format!("退出码: {} · 运行错误", payload.exit_code.unwrap_or(-1)),
|
format!(
|
||||||
|
"耗时: {}ms · 退出码: {} · 运行错误",
|
||||||
|
payload.duration_ms,
|
||||||
|
payload.exit_code.unwrap_or(-1)
|
||||||
|
),
|
||||||
"运行错误".to_string(),
|
"运行错误".to_string(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -231,7 +231,7 @@ pub async fn run_in_container(
|
|||||||
|
|
||||||
/// 流式输出 chunk:run_in_container_stream 边读日志边推送给 SSE handler。
|
/// 流式输出 chunk:run_in_container_stream 边读日志边推送给 SSE handler。
|
||||||
///
|
///
|
||||||
/// 序列化后作为 SSE event data;`Done` 同时携带终态信息(退出码 / OOM / 超时)。
|
/// 序列化后作为 SSE event data;`Done` 同时携带终态信息(退出码 / OOM / 超时 / 耗时)。
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum OutputChunk {
|
pub enum OutputChunk {
|
||||||
/// stdout 块(容器逐块产出)。
|
/// stdout 块(容器逐块产出)。
|
||||||
@ -239,10 +239,12 @@ pub enum OutputChunk {
|
|||||||
/// stderr 块(容器逐块产出)。
|
/// stderr 块(容器逐块产出)。
|
||||||
Stderr(String),
|
Stderr(String),
|
||||||
/// 终态:容器执行结束。exit_code=None 表示拿不到退出码(wait 出错)。
|
/// 终态:容器执行结束。exit_code=None 表示拿不到退出码(wait 出错)。
|
||||||
|
/// duration_ms = start_container 到 wait 完成的耗时。
|
||||||
Done {
|
Done {
|
||||||
exit_code: Option<i64>,
|
exit_code: Option<i64>,
|
||||||
oom_killed: bool,
|
oom_killed: bool,
|
||||||
timed_out: bool,
|
timed_out: bool,
|
||||||
|
duration_ms: u64,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,6 +322,9 @@ pub async fn run_in_container_stream(
|
|||||||
.start_container(&container_id, None::<StartContainerOptions>)
|
.start_container(&container_id, None::<StartContainerOptions>)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// 容器开始执行的时刻,用于计算 duration_ms(start_container 返回即视为起点)。
|
||||||
|
let start_time = std::time::Instant::now();
|
||||||
|
|
||||||
// 写入源码到 stdin 后关闭 writer。
|
// 写入源码到 stdin 后关闭 writer。
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
let write_fut = async {
|
let write_fut = async {
|
||||||
@ -477,12 +482,14 @@ pub async fn run_in_container_stream(
|
|||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
// 推送终态 chunk(客户端已断开则跳过,send 必然失败)。
|
// 推送终态 chunk(客户端已断开则跳过,send 必然失败)。
|
||||||
|
let duration_ms = start_time.elapsed().as_millis() as u64;
|
||||||
if !client_disconnected {
|
if !client_disconnected {
|
||||||
let _ = tx
|
let _ = tx
|
||||||
.send(OutputChunk::Done {
|
.send(OutputChunk::Done {
|
||||||
exit_code,
|
exit_code,
|
||||||
oom_killed,
|
oom_killed,
|
||||||
timed_out,
|
timed_out,
|
||||||
|
duration_ms,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user