use std::sync::Arc;
use std::time::{Duration, Instant};
use serde_json::Value;
use super::runner::{TraceCapture, run_for_channel};
#[derive(Debug)]
pub enum RunOutcome {
Ok,
WorkflowErrors(String),
Timeout(u64),
EngineError(dataflow_rs::DataflowError),
}
impl RunOutcome {
pub fn status_label(&self) -> &'static str {
match self {
Self::Ok => "ok",
Self::WorkflowErrors(_) | Self::EngineError(_) => "error",
Self::Timeout(_) => "timeout",
}
}
pub fn is_ok(&self) -> bool {
matches!(self, Self::Ok)
}
}
#[derive(Default)]
pub struct ExecOpts<'a> {
pub timeout_ms: Option<u64>,
pub capture: Option<TraceCapture>,
pub routing_bucket: Option<u8>,
pub profile: Option<&'a Arc<super::profile::ProfileCollector>>,
}
pub struct Execution {
pub message: dataflow_rs::Message,
pub task_trace: Option<dataflow_rs::ExecutionTrace>,
pub outcome: RunOutcome,
pub duration: Duration,
}
pub async fn execute_admitted(
engine: &super::EngineHandle,
channel: &str,
data: &Value,
metadata: &Value,
opts: ExecOpts<'_>,
) -> Execution {
let mut builder = dataflow_rs::Message::builder()
.payload_json(data)
.metadata_json(metadata);
if let Some(bucket) = opts.routing_bucket {
builder = builder.routing_bucket(bucket);
}
let mut message = builder.build();
let engine = engine.load();
let started = Instant::now();
let call = run_for_channel(
&engine,
channel,
&mut message,
opts.timeout_ms,
opts.profile,
opts.capture,
)
.await;
let duration = started.elapsed();
let (outcome, task_trace) = match call {
Err(ms) => (RunOutcome::Timeout(ms), None),
Ok((Err(e), trace)) => (RunOutcome::EngineError(e), trace),
Ok((Ok(()), trace)) => {
if message.has_errors() {
(RunOutcome::WorkflowErrors(error_summary(&message)), trace)
} else {
(RunOutcome::Ok, trace)
}
}
};
Execution {
message,
task_trace,
outcome,
duration,
}
}
fn error_summary(message: &dataflow_rs::Message) -> String {
message
.errors()
.iter()
.map(|e| format!("{}: {}", e.code, e.message))
.collect::<Vec<_>>()
.join("; ")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_status_label_is_one_derivation() {
assert_eq!(RunOutcome::Ok.status_label(), "ok");
assert_eq!(RunOutcome::Timeout(50).status_label(), "timeout");
assert_eq!(
RunOutcome::WorkflowErrors("boom".into()).status_label(),
"error"
);
assert_eq!(
RunOutcome::EngineError(dataflow_rs::DataflowError::Unknown("x".into())).status_label(),
"error"
);
}
}