Skip to content

Commit

Permalink
Merge pull request #6 from dapper91/dev
Browse files Browse the repository at this point in the history
- Library api reimplemented.
- Tests added.
- github actions added.
  • Loading branch information
dapper91 authored Nov 20, 2021
2 parents 068ce4f + 35192f0 commit 8a3c788
Show file tree
Hide file tree
Showing 15 changed files with 716 additions and 160 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: release

on:
release:
types:
- released

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: Build and publish
run: |
cargo login ${{ secrets.CRATESIO_TOKEN }}
cargo publish
21 changes: 21 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: test

on:
pull_request:
branches:
- dev
- master
push:
branches:
- master

jobs:
test:
name: Test coachman
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
run: rustup update stable
- name: Run tests
run: cargo test
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[package]
name = "coachman"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
license = "Unlicense"
description = "rust asynchronous task manager built on top of tokio framework"
readme = "README.rst"
readme = "README.md"

homepage = "https://github.com/dapper91/coachman-rs"
documentation = "https://docs.rs/coachman/"
Expand Down
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# CoachMan

![coachman](img/logo.png)

`coachman` is a rust asynchronous task manager built on top of tokio framework.

## Features

* **Task count control:**
`coachman` allows you to control task count preventing your application from uncontrolled task count explosion.
* **Task cancellation:**
The main feature of `coachman` is task cancellation. It provides a simple api for making your task cancelable.

# Basic example

The main feature of coachman is making asynchronous tasks cancelable.

Look at the following example:

``` rust
use coachman as cm;
use coachman::{try_await, Canceled, Completed, TaskError};

async fn inner_func(i: usize, duration: u64) {
match try_await!(tokio::time::sleep(std::time::Duration::from_secs(duration))) {
Canceled => println!("task#{} inner canceled", i),
Completed(_) => println!("task#{} inner completed", i),
}
}

async fn outer_func(i: usize, duration: u64) {
match try_await!(inner_func(i, duration)) {
Canceled => println!("task#{} outer canceled", i),
Completed(_) => println!("task#{} outer completed", i),
}
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
let mut task_handles = Vec::new();
for i in 0..5 {
let duration = i as u64;
task_handles.push(cm::spawn(outer_func(i, duration)));
}

let deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(2);
for (i, mut handle) in task_handles.into_iter().enumerate() {
if tokio::time::timeout_at(deadline, &mut handle).await.is_ok() {
println!("task-{} completed", i);
} else {
handle.cancel();
match handle.await {
Result::Err(TaskError::Canceled) => println!("task-{} canceled", i),
Result::Err(TaskError::Aborted) => println!("task-{} aborted", i),
Result::Err(TaskError::Panicked(_)) => println!("task-{} panicked", i),
Result::Ok(_) => unreachable!(),
}
}
}
}
```
54 changes: 0 additions & 54 deletions README.rst

This file was deleted.

40 changes: 40 additions & 0 deletions examples/cancelation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use coachman as cm;
use coachman::{try_await, Canceled, Completed, TaskError};

async fn inner_func(i: usize, duration: u64) {
match try_await!(tokio::time::sleep(std::time::Duration::from_secs(duration))) {
Canceled => println!("task#{} inner canceled", i),
Completed(_) => println!("task#{} inner completed", i),
}
}

async fn outer_func(i: usize, duration: u64) {
match try_await!(inner_func(i, duration)) {
Canceled => println!("task#{} outer canceled", i),
Completed(_) => println!("task#{} outer completed", i),
}
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
let mut task_handles = Vec::new();
for i in 0..5 {
let duration = i as u64;
task_handles.push(cm::spawn(outer_func(i, duration)));
}

let deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(2);
for (i, mut handle) in task_handles.into_iter().enumerate() {
if tokio::time::timeout_at(deadline, &mut handle).await.is_ok() {
println!("task-{} completed", i);
} else {
handle.cancel();
match handle.await {
Result::Err(TaskError::Canceled) => println!("task-{} canceled", i),
Result::Err(TaskError::Aborted) => println!("task-{} aborted", i),
Result::Err(TaskError::Panicked(_)) => println!("task-{} panicked", i),
Result::Ok(_) => unreachable!(),
}
}
}
}
26 changes: 15 additions & 11 deletions examples/cancel.rs → examples/task_manager.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
use coachman as cm;
use coachman::try_await;
use coachman::{Cancelled, Completed};
use coachman::{Canceled, Completed};
use std::time;

async fn function(i: usize) {
async fn inner(i: usize) {
match try_await!(tokio::time::sleep(time::Duration::from_secs(i as u64))) {
Cancelled => println!("task#{} cancelled", i),
Completed(_) => println!("task#{} completed", i),
Canceled => println!("task#{} inner canceled", i),
Completed(_) => println!("task#{} inner completed", i),
};
}

async fn outer(i: usize) {
match try_await!(inner(i)) {
Canceled => println!("task#{} outer canceled", i),
Completed(_) => println!("task#{} outer completed", i),
}

println!("task#{} canceled: {}", i, cm::is_task_canceled());
}
Expand All @@ -18,22 +25,19 @@ async fn main() {

let mut task_keys = Vec::new();
for i in 0..10 {
let task_key = task_manager.try_spawn(function(i)).unwrap();
let task_key = task_manager.try_spawn(outer(i)).unwrap();
task_keys.push(task_key)
}

tokio::time::timeout(time::Duration::from_secs(5), task_manager.process()).await;

let mut task_handles = Vec::new();
for task_key in task_keys {
if let Some(handle) = task_manager.cancel_task(task_key) {
task_handles.push(handle);
if task_manager.cancel_task(task_key).is_ok() {
println!("task-{} canceled", task_key)
} else {
println!("task-{} already finished", task_key)
}
}

for task_handle in task_handles {
task_handle.await;
}
task_manager.join(true).await;
}
Binary file removed img/logo-doc.png
Binary file not shown.
Binary file added img/logo-large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/logo-small.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 33 additions & 30 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,60 @@
//! * **Task count control:**
//! `coachman` allows you to control task count preventing your application from uncontrolled task count explosion.
//! * **Task cancellation:**
//! The main feature of `coachman` is task cancellation. It provides a simple api for making your task cancellable.
//! The main feature of `coachman` is task cancellation. It provides a simple api for making your task cancelable.
//!
//! # Basic example
//!
//! The main feature of coachman is making asynchronous tasks cancellable.
//! The main feature of coachman is making asynchronous tasks cancelable.
//! Look at the following example:
//!
//! ```
//! use coachman as cm;
//! use coachman::try_await;
//! use coachman::AwaitResult::{Cancelled, Completed};
//! use std::time;
//! use coachman::{try_await, Canceled, Completed, TaskError};
//!
//! async fn function(i: usize) {
//! match try_await!(tokio::time::sleep(time::Duration::from_secs(i as u64))) {
//! Cancelled => println!("task#{} cancelled", i),
//! Completed(_) => println!("task#{} completed", i),
//! };
//! async fn inner_func(i: usize, duration: u64) {
//! match try_await!(tokio::time::sleep(std::time::Duration::from_secs(duration))) {
//! Canceled => println!("task#{} inner canceled", i),
//! Completed(_) => println!("task#{} inner completed", i),
//! }
//! }
//!
//! println!("task#{} canceled: {}", i, cm::is_task_canceled());
//! async fn outer_func(i: usize, duration: u64) {
//! match try_await!(inner_func(i, duration)) {
//! Canceled => println!("task#{} outer canceled", i),
//! Completed(_) => println!("task#{} outer completed", i),
//! }
//! }
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() {
//! let mut task_manager = cm::TaskManager::builder().with_max_tasks(10).with_capacity(10).build();
//!
//! let mut task_keys = Vec::new();
//! for i in 0..10 {
//! let task_key = task_manager.try_spawn(function(i)).unwrap();
//! task_keys.push(task_key)
//! let mut task_handles = Vec::new();
//! for i in 0..5 {
//! let duration = i as u64;
//! task_handles.push(cm::spawn(outer_func(i, duration)));
//! }
//!
//! tokio::time::timeout(time::Duration::from_secs(5), task_manager.process()).await;
//!
//! let mut task_handles = Vec::new();
//! for task_key in task_keys {
//! if let Some(handle) = task_manager.cancel_task(task_key) {
//! task_handles.push(handle);
//! let deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(2);
//! for (i, mut handle) in task_handles.into_iter().enumerate() {
//! if tokio::time::timeout_at(deadline, &mut handle).await.is_ok() {
//! println!("task-{} completed", i);
//! } else {
//! println!("task-{} already finished", task_key)
//! handle.cancel();
//! match handle.await {
//! Result::Err(TaskError::Canceled) => println!("task-{} canceled", i),
//! Result::Err(TaskError::Aborted) => println!("task-{} aborted", i),
//! Result::Err(TaskError::Panicked(_)) => println!("task-{} panicked", i),
//! Result::Ok(_) => unreachable!(),
//! }
//! }
//! }
//!
//! for task_handle in task_handles {
//! task_handle.await;
//! }
//! }
//! ```
pub mod macros;
pub mod manager;
pub mod task;

pub use macros::AwaitResult::{self, Cancelled, Completed};
pub use manager::{is_task_canceled, TaskBuilder, TaskManager};
pub use macros::AwaitResult::{self, Canceled, Completed};
pub use manager::{TaskBuilder, TaskManager};
pub use task::{is_task_canceled, spawn, TaskError, TaskHandle};
Loading

0 comments on commit 8a3c788

Please sign in to comment.