Expose public task restart boundary
This commit is contained in:
parent
f586b48893
commit
0b14889c79
5 changed files with 419 additions and 8 deletions
|
|
@ -368,6 +368,7 @@ struct ProcessCancelArgs {
|
|||
#[derive(Clone, Debug, Subcommand)]
|
||||
enum TaskCommands {
|
||||
List(TaskListArgs),
|
||||
Restart(TaskRestartArgs),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Parser)]
|
||||
|
|
@ -378,6 +379,17 @@ struct TaskListArgs {
|
|||
process: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Parser)]
|
||||
struct TaskRestartArgs {
|
||||
#[command(flatten)]
|
||||
scope: CliScopeArgs,
|
||||
task: String,
|
||||
#[arg(long, default_value = "vp-current")]
|
||||
process: String,
|
||||
#[arg(long)]
|
||||
yes: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Parser)]
|
||||
struct LogsArgs {
|
||||
#[command(flatten)]
|
||||
|
|
@ -1307,6 +1319,44 @@ fn task_list_report(args: TaskListArgs) -> Result<Value> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn task_restart_report(args: TaskRestartArgs) -> Result<Value> {
|
||||
if let Some(coordinator) = &args.scope.coordinator {
|
||||
let mut session = JsonLineSession::connect(coordinator)?;
|
||||
let response = session.request_allow_error(json!({
|
||||
"type": "restart_task",
|
||||
"tenant": args.scope.tenant,
|
||||
"project": args.scope.project,
|
||||
"actor_user": args.scope.user,
|
||||
"process": args.process,
|
||||
"task": args.task,
|
||||
}))?;
|
||||
let restart_request = task_restart_request_summary(&response, !args.yes);
|
||||
return Ok(json!({
|
||||
"command": "task restart",
|
||||
"coordinator": coordinator,
|
||||
"process": args.process,
|
||||
"task": args.task,
|
||||
"requires_confirmation": !args.yes,
|
||||
"restart_request": restart_request,
|
||||
"response": response,
|
||||
"coordinator_session_requests": session.requests(),
|
||||
}));
|
||||
}
|
||||
Ok(json!({
|
||||
"command": "task restart",
|
||||
"status": "requires_coordinator",
|
||||
"requires_confirmation": !args.yes,
|
||||
"process": args.process,
|
||||
"task": args.task,
|
||||
"restart_request": {
|
||||
"status": "requires_coordinator",
|
||||
"operation": "restart_selected_task",
|
||||
"explicit_user_action": true,
|
||||
"clean_boundary_required": true,
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
fn logs_report(args: LogsArgs) -> Result<Value> {
|
||||
let events = list_task_events_if_available(
|
||||
args.scope.coordinator.as_deref(),
|
||||
|
|
@ -2048,11 +2098,18 @@ fn main() -> Result<()> {
|
|||
};
|
||||
emit_report(&report, json_output)?;
|
||||
}
|
||||
Commands::Task {
|
||||
command: TaskCommands::List(args),
|
||||
} => {
|
||||
let json_output = args.scope.json;
|
||||
emit_report(&task_list_report(args)?, json_output)?;
|
||||
Commands::Task { command } => {
|
||||
let (report, json_output) = match command {
|
||||
TaskCommands::List(args) => {
|
||||
let json_output = args.scope.json;
|
||||
(task_list_report(args)?, json_output)
|
||||
}
|
||||
TaskCommands::Restart(args) => {
|
||||
let json_output = args.scope.json;
|
||||
(task_restart_report(args)?, json_output)
|
||||
}
|
||||
};
|
||||
emit_report(&report, json_output)?;
|
||||
}
|
||||
Commands::Logs(args) => {
|
||||
let json_output = args.scope.json;
|
||||
|
|
@ -2592,6 +2649,49 @@ fn process_cancel_request_summary(response: &Value, requires_confirmation: bool)
|
|||
})
|
||||
}
|
||||
|
||||
fn task_restart_request_summary(response: &Value, requires_confirmation: bool) -> Value {
|
||||
if response.get("type").and_then(Value::as_str) != Some("task_restart") {
|
||||
return json!({
|
||||
"status": response.get("type").and_then(Value::as_str).unwrap_or("coordinator_response"),
|
||||
"operation": "restart_selected_task",
|
||||
"accepted": false,
|
||||
"requires_confirmation": requires_confirmation,
|
||||
"explicit_user_action": true,
|
||||
"clean_boundary_required": true,
|
||||
"error": response.get("message").cloned().unwrap_or(Value::Null),
|
||||
});
|
||||
}
|
||||
|
||||
json!({
|
||||
"status": "task_restart",
|
||||
"operation": "restart_selected_task",
|
||||
"accepted": response.get("accepted").cloned().unwrap_or_else(|| json!(false)),
|
||||
"process": response.get("process").cloned().unwrap_or(Value::Null),
|
||||
"task": response.get("task").cloned().unwrap_or(Value::Null),
|
||||
"requires_confirmation": requires_confirmation,
|
||||
"explicit_user_action": true,
|
||||
"clean_boundary_required": true,
|
||||
"clean_boundary_available": response
|
||||
.get("clean_boundary_available")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| json!(false)),
|
||||
"active_task": response
|
||||
.get("active_task")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| json!(false)),
|
||||
"completed_event_observed": response
|
||||
.get("completed_event_observed")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| json!(false)),
|
||||
"requires_whole_process_restart": response
|
||||
.get("requires_whole_process_restart")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| json!(true)),
|
||||
"message": response.get("message").cloned().unwrap_or(Value::Null),
|
||||
"website_required": false,
|
||||
})
|
||||
}
|
||||
|
||||
fn artifact_download_session_summary(response: &Value) -> Value {
|
||||
if response.get("type").and_then(Value::as_str) != Some("artifact_download_link") {
|
||||
return json!({
|
||||
|
|
@ -4368,6 +4468,7 @@ mod tests {
|
|||
&["disasmer", "process", "restart", "--yes"],
|
||||
&["disasmer", "process", "cancel", "--yes"],
|
||||
&["disasmer", "task", "list"],
|
||||
&["disasmer", "task", "restart", "compile-linux", "--yes"],
|
||||
&["disasmer", "logs"],
|
||||
&["disasmer", "artifact", "list"],
|
||||
&["disasmer", "artifact", "download", "artifact"],
|
||||
|
|
@ -5191,6 +5292,60 @@ mod tests {
|
|||
assert_eq!(cancel["cancel_request"]["new_task_launches_blocked"], true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn task_restart_reports_clean_boundary_requirements() {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = listener.local_addr().unwrap().to_string();
|
||||
let server = std::thread::spawn(move || {
|
||||
let (mut stream, _) = listener.accept().unwrap();
|
||||
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
||||
let mut line = String::new();
|
||||
reader.read_line(&mut line).unwrap();
|
||||
assert!(line.contains(r#""type":"restart_task""#));
|
||||
assert!(line.contains(r#""tenant":"tenant""#));
|
||||
assert!(line.contains(r#""project":"project""#));
|
||||
assert!(line.contains(r#""actor_user":"user""#));
|
||||
assert!(line.contains(r#""process":"vp""#));
|
||||
assert!(line.contains(r#""task":"compile-linux""#));
|
||||
stream
|
||||
.write_all(
|
||||
br#"{"type":"task_restart","process":"vp","task":"compile-linux","actor":"user","accepted":false,"clean_boundary_available":false,"active_task":true,"completed_event_observed":false,"requires_whole_process_restart":true,"message":"selected task is still active; clean task restart requires a captured checkpoint boundary"}"#,
|
||||
)
|
||||
.unwrap();
|
||||
stream.write_all(b"\n").unwrap();
|
||||
});
|
||||
|
||||
let report = task_restart_report(TaskRestartArgs {
|
||||
scope: CliScopeArgs {
|
||||
coordinator: Some(addr),
|
||||
tenant: "tenant".to_owned(),
|
||||
project: "project".to_owned(),
|
||||
user: "user".to_owned(),
|
||||
json: false,
|
||||
},
|
||||
task: "compile-linux".to_owned(),
|
||||
process: "vp".to_owned(),
|
||||
yes: true,
|
||||
})
|
||||
.unwrap();
|
||||
server.join().unwrap();
|
||||
|
||||
assert_eq!(report["command"], "task restart");
|
||||
assert_eq!(
|
||||
report["restart_request"]["operation"],
|
||||
"restart_selected_task"
|
||||
);
|
||||
assert_eq!(report["restart_request"]["accepted"], false);
|
||||
assert_eq!(report["restart_request"]["clean_boundary_available"], false);
|
||||
assert_eq!(
|
||||
report["restart_request"]["requires_whole_process_restart"],
|
||||
true
|
||||
);
|
||||
assert_eq!(report["restart_request"]["active_task"], true);
|
||||
assert_eq!(report["restart_request"]["website_required"], false);
|
||||
assert_eq!(report["coordinator_session_requests"], 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_command_reuses_bundle_inspection_without_full_repo_upload() {
|
||||
let temp = tempfile::tempdir().unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue