use crate::database::UniversalUuid;
use std::time::Duration;
use thiserror::Error;
#[derive(Debug, Clone)]
pub struct TaskReadyEvent {
pub task_execution_id: UniversalUuid,
pub workflow_execution_id: UniversalUuid,
pub task_name: String,
pub attempt: i32,
}
impl TaskReadyEvent {
pub fn new(
task_execution_id: UniversalUuid,
workflow_execution_id: UniversalUuid,
task_name: String,
attempt: i32,
) -> Self {
Self {
task_execution_id,
workflow_execution_id,
task_name,
attempt,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExecutionStatus {
Completed,
Failed,
Retry,
Skipped,
}
#[derive(Debug)]
pub struct ExecutionResult {
pub task_execution_id: UniversalUuid,
pub status: ExecutionStatus,
pub error: Option<String>,
pub duration: Duration,
}
impl ExecutionResult {
pub fn success(task_execution_id: UniversalUuid, duration: Duration) -> Self {
Self {
task_execution_id,
status: ExecutionStatus::Completed,
error: None,
duration,
}
}
pub fn failure(
task_execution_id: UniversalUuid,
error: impl Into<String>,
duration: Duration,
) -> Self {
Self {
task_execution_id,
status: ExecutionStatus::Failed,
error: Some(error.into()),
duration,
}
}
pub fn skipped(task_execution_id: UniversalUuid) -> Self {
Self {
task_execution_id,
status: ExecutionStatus::Skipped,
error: None,
duration: Duration::ZERO,
}
}
pub fn retry(
task_execution_id: UniversalUuid,
error: impl Into<String>,
duration: Duration,
) -> Self {
Self {
task_execution_id,
status: ExecutionStatus::Retry,
error: Some(error.into()),
duration,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ExecutorMetrics {
pub active_tasks: usize,
pub max_concurrent: usize,
pub total_executed: u64,
pub total_failed: u64,
pub avg_duration_ms: u64,
}
impl ExecutorMetrics {
pub fn available_capacity(&self) -> usize {
self.max_concurrent.saturating_sub(self.active_tasks)
}
}
#[derive(Debug, Clone)]
pub struct RoutingConfig {
pub default_executor: String,
pub rules: Vec<RoutingRule>,
}
impl Default for RoutingConfig {
fn default() -> Self {
Self {
default_executor: "default".to_string(),
rules: Vec::new(),
}
}
}
impl RoutingConfig {
pub fn new(default_executor: impl Into<String>) -> Self {
Self {
default_executor: default_executor.into(),
rules: Vec::new(),
}
}
pub fn with_rule(mut self, rule: RoutingRule) -> Self {
self.rules.push(rule);
self
}
pub fn with_rules(mut self, rules: impl IntoIterator<Item = RoutingRule>) -> Self {
self.rules.extend(rules);
self
}
}
#[derive(Debug, Clone)]
pub struct RoutingRule {
pub task_pattern: String,
pub executor: String,
}
impl RoutingRule {
pub fn new(task_pattern: impl Into<String>, executor: impl Into<String>) -> Self {
Self {
task_pattern: task_pattern.into(),
executor: executor.into(),
}
}
}
#[derive(Debug, Error)]
pub enum DispatchError {
#[error("Executor not found: {0}")]
ExecutorNotFound(String),
#[error("Task execution failed: {0}")]
ExecutionFailed(String),
#[error("Database error: {0}")]
DatabaseError(#[from] crate::error::ExecutorError),
#[error("Context error: {0}")]
ContextError(#[from] crate::error::ContextError),
#[error("Validation error: {0}")]
ValidationError(#[from] crate::error::ValidationError),
#[error("Executor has no capacity: {0}")]
NoCapacity(String),
#[error("Task not found: {0}")]
TaskNotFound(UniversalUuid),
}