taskflow-rs 0.1.1

A high-performance, async-first task orchestration framework for Rust
Documentation
use std::process::Stdio;
use tokio::process::Command;
use tracing::{error, info};

use crate::error::{Result, TaskFlowError};
use crate::task::{Task, TaskHandler, TaskResult};

pub struct PythonTaskHandler;

impl PythonTaskHandler {
    pub fn new() -> Self {
        Self
    }
}

#[async_trait::async_trait]
impl TaskHandler for PythonTaskHandler {
    fn task_type(&self) -> &'static str {
        "python_script"
    }

    async fn execute(&self, task: &Task) -> Result<TaskResult> {
        let script_content = task
            .definition
            .payload
            .get("script")
            .and_then(|v| v.as_str())
            .ok_or_else(|| {
                TaskFlowError::InvalidConfiguration("Missing script content".to_string())
            })?;

        let args = task
            .definition
            .payload
            .get("args")
            .and_then(|v| v.as_array())
            .map(|arr| {
                arr.iter()
                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
                    .collect::<Vec<String>>()
            })
            .unwrap_or_default();

        info!(
            "Executing Python script: {} with args: {:?}",
            task.definition.id, args
        );

        let mut cmd = Command::new("python3");
        cmd.arg("-c").arg(script_content);
        cmd.args(&args);
        cmd.stdin(Stdio::null());
        cmd.stdout(Stdio::piped());
        cmd.stderr(Stdio::piped());

        let output = cmd
            .output()
            .await
            .map_err(|e| TaskFlowError::ExecutionError(e.to_string()))?;

        let success = output.status.success();
        let stdout = String::from_utf8_lossy(&output.stdout).to_string();
        let stderr = String::from_utf8_lossy(&output.stderr).to_string();

        if !success {
            error!("Python script execution failed: {}", stderr);
        }

        Ok(TaskResult {
            success,
            output: Some(stdout),
            error: if stderr.is_empty() {
                None
            } else {
                Some(stderr)
            },
            execution_time_ms: 0,
            metadata: Default::default(),
        })
    }
}