wfe-core 1.9.2

Core traits, models, builder, and executor for the WFE workflow engine
Documentation
use async_trait::async_trait;

use crate::models::{ExecutionResult, WorkflowInstance};
use crate::traits::step::StepExecutionContext;

/// Workflow-level middleware with default no-op implementations.
#[async_trait]
pub trait WorkflowMiddleware: Send + Sync {
    async fn pre_workflow(&self, _instance: &WorkflowInstance) -> crate::Result<()> {
        Ok(())
    }
    async fn post_workflow(&self, _instance: &WorkflowInstance) -> crate::Result<()> {
        Ok(())
    }
}

/// Step-level middleware with default no-op implementations.
#[async_trait]
pub trait StepMiddleware: Send + Sync {
    async fn pre_step(&self, _context: &StepExecutionContext<'_>) -> crate::Result<()> {
        Ok(())
    }
    async fn post_step(
        &self,
        _context: &StepExecutionContext<'_>,
        _result: &ExecutionResult,
    ) -> crate::Result<()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::models::{ExecutionPointer, ExecutionResult, WorkflowInstance};

    struct NoOpWorkflowMiddleware;
    impl WorkflowMiddleware for NoOpWorkflowMiddleware {}

    struct NoOpStepMiddleware;
    impl StepMiddleware for NoOpStepMiddleware {}

    #[tokio::test]
    async fn workflow_middleware_default_pre_workflow() {
        let mw = NoOpWorkflowMiddleware;
        let instance = WorkflowInstance::new("wf", 1, serde_json::json!({}));
        mw.pre_workflow(&instance).await.unwrap();
    }

    #[tokio::test]
    async fn workflow_middleware_default_post_workflow() {
        let mw = NoOpWorkflowMiddleware;
        let instance = WorkflowInstance::new("wf", 1, serde_json::json!({}));
        mw.post_workflow(&instance).await.unwrap();
    }

    #[tokio::test]
    async fn step_middleware_default_pre_step() {
        use crate::models::WorkflowStep;
        let mw = NoOpStepMiddleware;
        let instance = WorkflowInstance::new("wf", 1, serde_json::json!({}));
        let pointer = ExecutionPointer::new(0);
        let step = WorkflowStep::new(0, "test_step");
        let ctx = StepExecutionContext {
            definition: None,
            item: None,
            execution_pointer: &pointer,
            persistence_data: None,
            step: &step,
            workflow: &instance,
            cancellation_token: tokio_util::sync::CancellationToken::new(),
            host_context: None,
            log_sink: None,
        };
        mw.pre_step(&ctx).await.unwrap();
    }

    #[tokio::test]
    async fn step_middleware_default_post_step() {
        use crate::models::WorkflowStep;
        let mw = NoOpStepMiddleware;
        let instance = WorkflowInstance::new("wf", 1, serde_json::json!({}));
        let pointer = ExecutionPointer::new(0);
        let step = WorkflowStep::new(0, "test_step");
        let ctx = StepExecutionContext {
            definition: None,
            item: None,
            execution_pointer: &pointer,
            persistence_data: None,
            step: &step,
            workflow: &instance,
            cancellation_token: tokio_util::sync::CancellationToken::new(),
            host_context: None,
            log_sink: None,
        };
        let result = ExecutionResult::next();
        mw.post_step(&ctx, &result).await.unwrap();
    }
}