refactor: split run_process in executor
This commit is contained in:
parent
71c2b9dc63
commit
9f7c81644d
|
@ -4,7 +4,7 @@ use log::{debug, info, error};
|
||||||
use sqlx::{Pool, QueryBuilder, Sqlite};
|
use sqlx::{Pool, QueryBuilder, Sqlite};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use std::process::Stdio;
|
use std::process::{ExitStatus, Stdio};
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncRead, BufReader};
|
use tokio::io::{AsyncBufReadExt, AsyncRead, BufReader};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use tokio::sync::mpsc::Receiver;
|
||||||
|
@ -16,7 +16,6 @@ async fn insert_logs(db: &Pool<Sqlite>, collected_logs: &mut Vec<LogLine>) -> Re
|
||||||
if collected_logs.is_empty() {
|
if collected_logs.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// insert into sqlite dB
|
|
||||||
let mut query_builder = QueryBuilder::new("INSERT INTO logs_lines (id, task_run_id, captured_at, kind, content)");
|
let mut query_builder = QueryBuilder::new("INSERT INTO logs_lines (id, task_run_id, captured_at, kind, content)");
|
||||||
query_builder.push_values(collected_logs.iter(), |mut b, log_line| {
|
query_builder.push_values(collected_logs.iter(), |mut b, log_line| {
|
||||||
b
|
b
|
||||||
|
@ -35,8 +34,12 @@ fn collect_logs<Stream>(task_run_id: Uuid, kind: LogKind, stream: Stream, db: Po
|
||||||
where Stream: AsyncRead + Unpin + std::marker::Send + 'static
|
where Stream: AsyncRead + Unpin + std::marker::Send + 'static
|
||||||
{
|
{
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut lines = BufReader::with_capacity(2048, stream).lines();
|
let mut lines = BufReader::with_capacity(1048, stream).lines();
|
||||||
let mut collected_logs: Vec<LogLine> = vec![];
|
let mut collected_logs: Vec<LogLine> = vec![];
|
||||||
|
let max_lines = match &kind {
|
||||||
|
LogKind::Stdout => 20,
|
||||||
|
LogKind::Stderr => 3
|
||||||
|
};
|
||||||
while let Some(line) = lines.next_line().await.unwrap() {
|
while let Some(line) = lines.next_line().await.unwrap() {
|
||||||
collected_logs.push(LogLine {
|
collected_logs.push(LogLine {
|
||||||
id: Uuid::new_v4().to_string(),
|
id: Uuid::new_v4().to_string(),
|
||||||
|
@ -45,40 +48,15 @@ fn collect_logs<Stream>(task_run_id: Uuid, kind: LogKind, stream: Stream, db: Po
|
||||||
task_run_id: task_run_id.to_string(),
|
task_run_id: task_run_id.to_string(),
|
||||||
captured_at: Utc::now().timestamp_millis(),
|
captured_at: Utc::now().timestamp_millis(),
|
||||||
});
|
});
|
||||||
if collected_logs.len() > 20 {
|
if collected_logs.len() > max_lines {
|
||||||
insert_logs(&db, &mut collected_logs).await.expect("Error inserting log");
|
insert_logs(&db, &mut collected_logs).await.expect("Error inserting logs.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insert_logs(&db, &mut collected_logs).await.expect("Error inserting log");
|
insert_logs(&db, &mut collected_logs).await.expect("Error inserting log");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_task(state: AppState, order: ExecutorOrder) -> Result<()> {
|
async fn execute_process(state: &AppState, order: &ExecutorOrder, cmd: &mut Command) -> Result<ExitStatus> {
|
||||||
debug!("Start processing of order {:?}", &order.id);
|
|
||||||
// save in DB
|
|
||||||
let _result = sqlx::query("INSERT INTO task_runs (id, task_id, trigger_mode, status, submitted_at, started_at) VALUES ($1, $2, $3, $4, $5, $5)")
|
|
||||||
.bind(order.id.to_string())
|
|
||||||
.bind(order.task_id.clone())
|
|
||||||
.bind(order.trigger_mode.to_string())
|
|
||||||
.bind(TaskStatus::Running.to_string())
|
|
||||||
.bind(Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true))
|
|
||||||
.execute(&state.db)
|
|
||||||
.await.unwrap();
|
|
||||||
|
|
||||||
let task = state.config.tasks.get(&order.task_id).expect("Task id to be valid");
|
|
||||||
let executable = match task.command.first() {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return Err(anyhow!("Could not find command to execute")),
|
|
||||||
};
|
|
||||||
let mut cmd = Command::new(executable);
|
|
||||||
|
|
||||||
cmd.args(task.command.iter().skip(1).collect::<Vec<&String>>())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(Stdio::piped());
|
|
||||||
for (key, val) in task.env.iter() {
|
|
||||||
cmd.env(key, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut child = cmd.spawn().expect("Failed to execute process");
|
let mut child = cmd.spawn().expect("Failed to execute process");
|
||||||
let child_stdout = child.stdout.take().unwrap(); // take is like clone
|
let child_stdout = child.stdout.take().unwrap(); // take is like clone
|
||||||
let child_stderr = child.stderr.take().unwrap();
|
let child_stderr = child.stderr.take().unwrap();
|
||||||
|
@ -93,22 +71,52 @@ async fn run_task(state: AppState, order: ExecutorOrder) -> Result<()> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// parallel stdout and stderr capture
|
// parallel stdout and stderr capture
|
||||||
let stdout_handle = collect_logs(
|
|
||||||
order.id,
|
|
||||||
LogKind::Stderr,
|
|
||||||
child_stderr,
|
|
||||||
state.db.clone()
|
|
||||||
);
|
|
||||||
let stderr_handle = collect_logs(
|
let stderr_handle = collect_logs(
|
||||||
order.id,
|
order.id,
|
||||||
LogKind::Stdout,
|
LogKind::Stdout,
|
||||||
child_stdout,
|
child_stdout,
|
||||||
state.db.clone()
|
state.db.clone()
|
||||||
);
|
);
|
||||||
|
let stdout_handle = collect_logs(
|
||||||
|
order.id,
|
||||||
|
LogKind::Stderr,
|
||||||
|
child_stderr,
|
||||||
|
state.db.clone()
|
||||||
|
);
|
||||||
|
|
||||||
stdout_handle.await?;
|
|
||||||
stderr_handle.await?;
|
stderr_handle.await?;
|
||||||
let status = process_handle.await?;
|
stdout_handle.await?;
|
||||||
|
return Ok(process_handle.await?);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_task(state: AppState, order: ExecutorOrder) -> Result<()> {
|
||||||
|
debug!("Start processing of order {:?}", &order.id);
|
||||||
|
// save in DB
|
||||||
|
let _result = sqlx::query("INSERT INTO task_runs (id, task_id, trigger_mode, status, submitted_at, started_at) VALUES ($1, $2, $3, $4, $5, $5)")
|
||||||
|
.bind(order.id.to_string())
|
||||||
|
.bind(order.task_id.clone())
|
||||||
|
.bind(order.trigger_mode.to_string())
|
||||||
|
.bind(TaskStatus::Running.to_string())
|
||||||
|
.bind(Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true))
|
||||||
|
.execute(&state.db)
|
||||||
|
.await.unwrap();
|
||||||
|
|
||||||
|
let task = state.config.tasks.get(&order.task_id)
|
||||||
|
.expect("Task id in executor order is not valid.");
|
||||||
|
let executable = match task.command.first() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Err(anyhow!("Could not find command to execute")),
|
||||||
|
};
|
||||||
|
let mut cmd = Command::new(executable);
|
||||||
|
|
||||||
|
cmd.args(task.command.iter().skip(1).collect::<Vec<&String>>())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped());
|
||||||
|
for (key, val) in task.env.iter() {
|
||||||
|
cmd.env(key, val);
|
||||||
|
}
|
||||||
|
let status = execute_process(&state, &order, &mut cmd).await?;
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
error!("Non successful exit code found: {}", status);
|
error!("Non successful exit code found: {}", status);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue