Skip to content

xpcn2015/tcrm-task

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TCRM Task

Async task execution unit for the TCRM project

Tested on Windows 10. Not tested on Unix.

Features

  • Asynchronous Execution: Built on Tokio for async task execution
  • Task Timeout: Configurable execution timeout
  • Event System: Real-time monitoring of task lifecycle and output
  • Optional Tracing/Logging: Enable structured logging with the tracing Cargo feature

Installation

Add this to your Cargo.toml:

[dependencies]
tcrm-task = { version = "0.3.2" }

Quick Start

Basic Task Execution

use tcrm_task::tasks::{
    config::TaskConfig,
    tokio::spawn::spawner::TaskSpawner,
    event::{TaskEvent, TaskEventEnvelope},
};
use tokio::sync::mpsc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = if cfg!(windows) {
        TaskConfig::new("powershell")
            .args(["-Command", "echo Hello from Windows!"])
            .timeout_ms(5000)
    } else {
        TaskConfig::new("bash")
            .args(["-c", "echo Hello from Unix!"])
            .timeout_ms(5000)
    };

    let mut spawner = TaskSpawner::new("hello_task".to_string(), config);

    // Create an event channel to receive task events
    let (event_tx, mut event_rx) = mpsc::channel::<TaskEventEnvelope>(100);

    // Start the task
    let process_id = spawner.start_direct(event_tx).await?;
    println!("Started process with ID: {}", process_id);

    // Listen for events
    while let Some(envelope) = event_rx.recv().await {
        match envelope.event {
            TaskEvent::Started { process_id, .. } => {
                println!("Task '{}' started with PID {}", envelope.id, process_id);
            }
            TaskEvent::Output { line, src, .. } => {
                println!("Task '{}' output ({:?}): {}", envelope.id, src, line);
            }
            TaskEvent::Stopped { exit_code, reason, .. } => {
                println!("Task '{}' stopped with exit code {:?}, reason: {:?}", 
                    envelope.id, exit_code, reason);
                break;
            }
            TaskEvent::Error { error } => {
                eprintln!("Task '{}' error: {}", envelope.id, error);
            }
            _ => {}
        }
    }
    Ok(())
}

More Configuration

use tcrm_task::tasks::config::TaskConfig;
use std::collections::HashMap;

let config = TaskConfig::new("cargo")
    .args(["build", "--release"])
    .working_dir("/path/to/project")
    .env([
        ("RUST_LOG", "debug"),
        ("CARGO_TARGET_DIR", "target")
    ])
    .timeout_ms(30000)  // 30 seconds
    .enable_stdin(true);

// Validate configuration before use
config.validate()?;

Task with Stdin Input

use tokio::sync::mpsc;

// Create stdin channel
let (stdin_tx, stdin_rx) = mpsc::channel::<String>(10);
let config = if cfg!(windows) {
    TaskConfig::new("powershell")
        .args(["-Command", "cat"])
        .enable_stdin(true)
} else {
    TaskConfig::new("cat")
        .enable_stdin(true)
};
let mut spawner = TaskSpawner::new("cat_task".to_string(), config)
    .set_stdin(stdin_rx);
stdin_tx.send("Hello from stdin!".to_string()).await?;

Task States

Tasks progress through the following states:

  • Pending: Task is created but not yet started
  • Initiating: Task is being prepared for execution
  • Running: Task is actively executing
  • Ready: Task is running and ready (for long-running processes)
  • Finished: Task has completed execution

Event System

The library provides real-time events for task monitoring:

use tcrm_task::tasks::event::{TaskEvent, TaskStopReason};

// Events are wrapped in TaskEventEnvelope
while let Some(envelope) = event_rx.recv().await {
    match envelope.event {
        TaskEvent::Started { process_id, .. } => {
            // Task has started
            println!("Task '{}' started with PID {}", envelope.id, process_id);
        }
        TaskEvent::Output { line, src, .. } => {
            // New output line from stdout or stderr
            println!("Task '{}' output: {}", envelope.id, line);
        }
        TaskEvent::Ready => {
            // Task is ready
            println!("Task '{}' is ready", envelope.id);
        }
        TaskEvent::Stopped { exit_code, reason, .. } => {
            // Task has stopped
            match reason {
                TaskStopReason::Finished => println!("Task '{}' completed normally", envelope.id),
                TaskStopReason::Terminated(reason) => println!("Task '{}' terminated: {:?}", envelope.id, reason),
                TaskStopReason::Error(err) => println!("Task '{}' failed: {}", envelope.id, err),
            }
        }
        TaskEvent::Error { error } => {
            // Task encountered an error
            eprintln!("Task '{}' error: {}", envelope.id, error);
        }
        _ => {}
    }
}

Features

Default Features

  • tokio: Enables async functionality (enabled by default)

Optional Features

  • flatbuffers: Enables FlatBuffers serialization support
  • tracing: Enables structured logging/tracing macros

Examples

See the examples/ directory for:

  • Basic process execution
  • Interactive process with stdin
  • Configuration validation
  • Tracing/logging output

Testing

Run the test suite:

# Run all tests
cargo test

# Run tests with logging/tracing
RUST_LOG=debug cargo test --features tracing

# Run specific test module
cargo test tasks::tests

License

This project is licensed under either the MIT or Apache-2.0 License, at your option.

See LICENSE file for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages