2 unstable releases

new 0.1.0 Dec 16, 2024
0.0.1-dev Dec 6, 2024

#217 in Concurrency

Download history 109/week @ 2024-12-05 126/week @ 2024-12-12

235 downloads per month

MIT license

37KB
679 lines

Sprinter 👟

A Rust library for running parallel queued tasks with controlled concurrency.

Features

  • ⚡ Run tasks in parallel with configurable concurrency limits
  • 🔄 Queue tasks and manage their execution
  • 📊 Track task states (Pending, Running, Succeed, Failed)
  • 🚦 Control task flow with push/wait mechanisms
  • 🔍 Monitor individual task completion and results

Installation

Add this to your Cargo.toml:

[dependencies]
sprinter = "0.0.1-dev"

Usage

Basic Example

Here's a basic example of using Sprinter to run parallel tasks:

use sprinter::Queue;
use std::fmt::Error;
use tokio::time::sleep;

#[tokio::main]
async fn main() {
    println!("sprint start ...");
    let start = tokio::time::Instant::now();
    // Create a queue with concurrency of 2 and tick interval of 50ms
    let queue: Queue<i32, Error> = Queue::new(2, 50);

    // Define some async tasks
    let task1 = || async {
        println!("task1 start ...");
        sleep(tokio::time::Duration::from_millis(250)).await;
        println!("task1 done!");
        Ok(1)
    };
    let task2 = || async {
        println!("task2 start ...");
        sleep(tokio::time::Duration::from_millis(50)).await;
        println!("task2 done!");
        Ok(2)
    };
    let task3 = || async {
        println!("task3 start ...");
        sleep(tokio::time::Duration::from_millis(50)).await;
        println!("task3 done!");
        Ok(3)
    };

    // Push tasks to the queue
    queue.push(&"task1".to_string(), task1).await.unwrap();
    queue.push(&"task2".to_string(), task2).await.unwrap();
    queue.push(&"task3".to_string(), task3).await.unwrap();

    // Signal that all tasks have been pushed
    queue.set_push_done().await;

    // Wait for all tasks to complete and get results
    let results = queue.wait_for_tasks_done().await;

    let end = tokio::time::Instant::now();
    println!("sprint done in {:?}", end - start);
    println!("results: {:?}", results);
}

It will print:

sprint start ...
task1 start ...
task2 start ...
task2 done!
task3 start ...
task3 done!
task1 done!
sprint done in 251.949651ms
results: {"task1": Ok(Ok(1)), "task2": Ok(Ok(2)), "task3": Ok(Ok(3))}

This will execute tasks in parallel with a maximum concurrency of 2, meaning two tasks can run simultaneously. The output will show tasks running and completing based on their duration and the concurrency limit.

API

Creating a Queue

let queue: Queue<T, E> = Queue::new(concurrency: usize, tick_interval: u64);
  • concurrency: Maximum number of tasks that can run in parallel
  • tick_interval: Interval in milliseconds between queue processing ticks
  • T: Type of successful task result
  • E: Type of task error

Methods

push

async fn push<F, R>(&self, task_id: &String, task: F) -> Result<(), QueueError>
where
    F: FnOnce() -> R + Send + 'static,
    R: Future<Output = Result<T, E>> + Send + 'static

Pushes a new task to the queue, it will be executed as soon as it is pushed or when the queue is ready. Each task must have a unique ID, tasks execution is deduped by task_id.

set_push_done

async fn set_push_done(&self)

Signals that all tasks have been pushed to the queue. Note the queue will not complete until set_push_done is called, even if all tasks have been completed.

task_done

async fn task_done(&self, task_id: &String) -> Result<Result<T, E>, QueueError>

Waits for a specific task to complete and returns its result.

wait_for_tasks_done

async fn wait_for_tasks_done(&self) -> HashMap<String, Result<Result<T, E>, QueueError>>

Waits for all tasks to complete and returns a map of task IDs to their results. set_push_done must be called before this method.

reset

async fn reset(&self)

Resets the queue to its initial state, clearing all tasks and results.

Task States

Tasks can be in one of these states:

  • Pending: Task is queued but not yet running
  • Running: Task is currently executing
  • Succeed: Task completed successfully
  • Failed: Task failed with an error

License

This project is licensed under the MIT License - see the LICENSE file for details.

Dependencies

~2.6–8.5MB
~74K SLoC