继续收敛受控命令进程错误
保留 leader 身份读取和进程组终止具体原因 保留主进程 kill、wait 与兜底终止正文
This commit is contained in:
@@ -155,9 +155,11 @@ impl ProjectCommandTree {
|
||||
let pid = child.id().ok_or("受控命令缺少进程身份")?;
|
||||
let start_identity =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map_err(|error| format!("受控命令 leader 启动身份读取失败:{error}"))?
|
||||
.filter(|identity| !identity.is_empty());
|
||||
if start_identity.is_none() {
|
||||
return Err("受控命令 leader 启动身份为空,拒绝接管进程组".into());
|
||||
}
|
||||
Ok(Self::Group {
|
||||
pid,
|
||||
start_identity,
|
||||
@@ -186,7 +188,7 @@ impl ProjectCommandTree {
|
||||
}
|
||||
let observed =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(*pid)
|
||||
.map_err(|_| "受控进程组 leader 身份未确认,拒绝发送终止信号")?;
|
||||
.map_err(|error| format!("受控进程组 leader 身份未确认:{error}"))?;
|
||||
if !owned_project_command_group_identity_matches(
|
||||
start_identity.as_deref(),
|
||||
observed.as_deref(),
|
||||
@@ -207,15 +209,23 @@ impl ProjectCommandTree {
|
||||
{
|
||||
let Self::Job(job) = self;
|
||||
let requested = job.terminate();
|
||||
if requested.is_err() {
|
||||
let _ = child.start_kill();
|
||||
}
|
||||
let fallback_error = requested
|
||||
.as_ref()
|
||||
.err()
|
||||
.and_then(|_| child.start_kill().err());
|
||||
let deadline = tokio::time::Instant::now() + Duration::from_secs(5);
|
||||
let waited = tokio::time::timeout_at(deadline, child.wait()).await;
|
||||
requested?;
|
||||
if let Err(error) = requested {
|
||||
return Err(match fallback_error {
|
||||
Some(fallback_error) => {
|
||||
format!("{error};主进程兜底终止失败:{fallback_error}")
|
||||
}
|
||||
None => error,
|
||||
});
|
||||
}
|
||||
waited
|
||||
.map_err(|_| "等待受控命令主进程退出超时")?
|
||||
.map_err(|_| "受控命令主进程退出未确认")?;
|
||||
.map_err(|_| "等待受控命令主进程退出超时:超过 5 秒".to_string())?
|
||||
.map_err(|error| format!("受控命令主进程退出未确认:{error}"))?;
|
||||
while !job.is_empty()? {
|
||||
if tokio::time::Instant::now() >= deadline {
|
||||
return Err("受控命令 Windows Job 子树退出未确认".into());
|
||||
@@ -228,11 +238,14 @@ impl ProjectCommandTree {
|
||||
{
|
||||
let deadline = tokio::time::Instant::now() + Duration::from_secs(5);
|
||||
let requested = self.request_owned_group_termination();
|
||||
let _ = child.start_kill();
|
||||
let child_kill_error = child.start_kill().err();
|
||||
let waited = tokio::time::timeout_at(deadline, child.wait()).await;
|
||||
let child_kill_detail = child_kill_error
|
||||
.map(|error| format!(";主进程兜底终止失败:{error}"))
|
||||
.unwrap_or_default();
|
||||
waited
|
||||
.map_err(|_| "等待受控命令主进程退出超时")?
|
||||
.map_err(|_| "受控命令主进程退出未确认")?;
|
||||
.map_err(|_| "等待受控命令主进程退出超时:超过 5 秒".to_string())?
|
||||
.map_err(|error| format!("受控命令主进程退出未确认:{error}{child_kill_detail}"))?;
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let Self::Group { pid, .. } = self;
|
||||
|
||||
@@ -93,3 +93,4 @@ DirectProject 回合失败在确认不是客户端内部不可归类故障时,
|
||||
- 策划工作区事件订阅失败仍有一处直接静默结束,导致文件刷新失联却没有提示;现把订阅 IPC 正文写入工作区错误状态,继续保留手动刷新与已有清单读取错误出口。
|
||||
- 新一轮原生扫出 app-server 进程与上下文漏损:Codex 执行器核验/OAuth 保存/回合身份的 JoinError、图片 base64 解码、Direct 上下文 canonicalize,以及进程树归属、Job、等待、终止和 Drop 清理错误原先只剩固定码;现保留 JoinError、解码器、OS/Job、等待和终止阶段正文,并为进程树 Drop 清理失败写入诊断日志。
|
||||
- 继续扫出浏览器收割的 Job/root kill/wait 错误原先压成 `bool`、External Editor 本机凭据 JSON/目录创建/保存错误丢底层正文,以及生成任务中断收口把项目清单读取失败当成“状态未知”;现分别保留浏览器清理阶段正文、凭据解析/存储正文,并让非“项目尚未初始化”的清单读取失败直接返回具体错误。
|
||||
- 受控 command 执行路径仍会把 leader 启动身份读取、进程组终止、root kill、Job/wait 失败折叠为“身份未确认/退出未确认”;现拒绝无身份接管并保留身份读取、终止兜底、等待和 OS 错误正文。
|
||||
|
||||
Reference in New Issue
Block a user