pub struct TaskExecutor { /* private fields */ }Expand description
A TaskExecutor provides a simple interface for spawning tasks onto a Tokio Runtime.
It holds a static reference to a Runtime, which acts as the task executor.
It also manages background workers for different types of batchable tasks, creating
them on demand. This design encourages treating the runtime as a shared, long-lived resource.
For creation, see TaskExecutor::new.
Implementations§
Source§impl TaskExecutor
impl TaskExecutor
Sourcepub fn new(rt: &'static Runtime) -> Self
pub fn new(rt: &'static Runtime) -> Self
Creates a new TaskExecutor instance bound to a statically-lived Tokio runtime.
An application will typically create a single Runtime instance that lives for the
duration of the program. To pass a reference of this runtime to the TaskExecutor,
it must have a 'static lifetime. This ensures the TaskExecutor can never outlive
the runtime it depends on.
§Arguments
rt: A static reference to atokio::runtime::Runtime.
§Example
use mini_executor::TaskExecutor;
use tokio::runtime::Runtime;
use std::sync::OnceLock;
// Use OnceLock to create a static runtime reference.
static RT: OnceLock<Runtime> = OnceLock::new();
fn main() {
let rt = RT.get_or_init(|| Runtime::new().unwrap());
let executor = TaskExecutor::new(rt);
// The task executor is now ready to execute tasks.
}Sourcepub async fn execute_waiting<T: Task>(
&self,
task: T,
) -> Result<T::Output, JoinError>
pub async fn execute_waiting<T: Task>( &self, task: T, ) -> Result<T::Output, JoinError>
Spawns an individual task and asynchronously waits for its result.
This method submits the task to the executor’s runtime and suspends the current async context until the task has finished.
§Arguments
task: An instance of a type that implements theTasktrait.
§Returns
A Result containing either:
Ok(T::Output): The successful output of the task.Err(JoinError): An error indicating that the task panicked during execution.
§Example
struct MyTask;
impl Task for MyTask {
type Output = u32;
async fn run(self) -> Self::Output { 42 }
}
let rt = RT.get_or_init(|| Runtime::new().unwrap());
let executor = TaskExecutor::new(rt);
rt.block_on(async {
let result = executor.execute_waiting(MyTask).await?;
assert_eq!(result, 42);
Ok::<(), Box<dyn std::error::Error>>(())
})?;Sourcepub fn execute_detached<T: Task>(&self, task: T) -> JoinHandle<T::Output>
pub fn execute_detached<T: Task>(&self, task: T) -> JoinHandle<T::Output>
Spawns an individual task and immediately returns a JoinHandle without awaiting it.
This is useful for “fire-and-forget” style execution, where the task runs
in the background. The returned JoinHandle can still be used to await the task’s
completion at a later point if its result is needed.
§Arguments
task: An instance of a type that implements theTasktrait.
§Returns
A JoinHandle representing the spawned task. Awaiting the handle will
yield a Result<T::Output, JoinError>.
§Example
struct BackgroundTask;
impl Task for BackgroundTask {
type Output = String;
async fn run(self) -> Self::Output { "done".to_string() }
}
let rt = RT.get_or_init(|| Runtime::new().unwrap());
let executor = TaskExecutor::new(rt);
rt.block_on(async {
// Spawn the task but don't wait for it yet.
let handle = executor.execute_detached(BackgroundTask);
// We can do other work here...
println!("Task is running in the background.");
// Later, await the handle to get the result.
let result = handle.await?;
assert_eq!(result, "done");
Ok::<(), Box<dyn std::error::Error>>(())
})?;Sourcepub fn execute_batch_detached<BT: BatchTask + Clone>(&self, batch_task: BT)
pub fn execute_batch_detached<BT: BatchTask + Clone>(&self, batch_task: BT)
Executes a batch task asynchronously without waiting for its completion.
This method submits a task to its corresponding batch processor. If a processor for this task type does not exist, one is spawned. The task will be collected with other pending tasks of the same type and executed in a single batch.
This is a “fire-and-forget” operation.
§Arguments
batch_task: An instance of a type that implementsBatchTask.
§Example
#[derive(Clone)]
struct LogMessage(String);
impl BatchTask for LogMessage {
async fn batch_run(list: Vec<Self>) {
// In a real app, this might write to a file or database.
println!("-- Logging batch of {} messages --", list.len());
for msg in list {
println!("{}", msg.0);
}
}
}
let rt = RT.get_or_init(|| Runtime::new().unwrap());
let executor = TaskExecutor::new(rt);
rt.block_on(async {
// Fire-and-forget these logging tasks.
executor.execute_batch_detached(LogMessage("User logged in".to_string()));
executor.execute_batch_detached(LogMessage("Data processed".to_string()));
// Give the batch processor a moment to run.
sleep(Duration::from_millis(50)).await;
});Sourcepub async fn execute_batch_waiting<BT: BatchTask + Clone>(
&self,
batch_task: BT,
) -> Result<(), RecvError>
pub async fn execute_batch_waiting<BT: BatchTask + Clone>( &self, batch_task: BT, ) -> Result<(), RecvError>
Executes a batch task and waits for its containing batch to complete.
This method submits a task to its batch processor and waits for a completion signal. The signal is sent after the entire batch (which includes this task) has finished processing.
§Arguments
batch_task: An instance of a type that implementsBatchTask.
§Returns
A Result which is Ok(()) on successful completion of the batch. It returns
Err(oneshot::error::RecvError) if the batch processor panics or is terminated
before sending a completion signal.
§Example
#[derive(Clone)]
struct DatabaseInsert(u32);
impl BatchTask for DatabaseInsert {
async fn batch_run(list: Vec<Self>) {
let ids: Vec<u32> = list.into_iter().map(|item| item.0).collect();
println!("BATCH INSERT: Simulating inserting IDs: {:?}", ids);
// In a real app, you'd perform the batched database query here.
}
}
let rt = RT.get_or_init(|| Runtime::new().unwrap());
let executor = TaskExecutor::new(rt);
rt.block_on(async {
// Detach a few tasks first.
executor.execute_batch_detached(DatabaseInsert(1));
executor.execute_batch_detached(DatabaseInsert(2));
// Now, execute a task and wait for its batch to complete.
// This task will be batched with the two above.
let result = executor.execute_batch_waiting(DatabaseInsert(3)).await;
assert!(result.is_ok());
println!("Batch confirmed as complete.");
});