Executor Model (Tokio vs. Fibers)
Relevant source files
The following files were used as context for generating this wiki page:
The Kodus Runtime features a flexible, multi-runtime executor model that allows for swapping between different asynchronous task execution backends. This design provides the ability to choose the best runtime for a given workload, with current support for the robust, multi-threaded Tokio runtime and a lightweight May (fiber-based) runtime. The selection is managed through configuration and compile-time features.
The core of this system is a generic Runtime trait that abstracts the specific implementations, ensuring that the rest of the application can spawn and manage tasks without being tightly coupled to a particular backend. This abstraction also provides a unified interface for health checks and configuration management across different runtimes.
Sources: README.md, apps/runtime/crates/core/src/executor/mod.rs
Core Abstraction: The Runtime Trait
The executor model is built around the Runtime trait, which defines the essential contract for any asynchronous runtime implementation within the Kodus ecosystem. This ensures consistent behavior for task spawning, shutdown, and monitoring.
Sources: apps/runtime/crates/core/src/executor/mod.rs:17-43
Trait Definition
// Source: apps/runtime/crates/core/src/executor/mod.rs:17-43
#[async_trait]
pub trait Runtime: Send + Sync {
fn spawn<Fut>(&self, fut: Fut) -> Pin<Box<dyn Future<Output = ()> + Send>>
where
Fut: Future<Output = ()> + Send + 'static;
fn spawn_with_priority<Fut>(
&self,
priority: u8,
fut: Fut,
) -> Pin<Box<dyn Future<Output = ()> + Send>>
where
Fut: Future<Output = ()> + Send + 'static;
async fn shutdown(&self) -> Result<(), ShutdownError>;
async fn health_check(&self) -> HealthStatus;
fn config(&self) -> &RuntimeConfig;
}
Key Methods
| Method | Description |
|---|---|
spawn | Spawns a future onto the runtime for execution. |
spawn_with_priority | Spawns a future with a given priority. The implementation may or may not use this priority level. |
shutdown | Initiates a graceful shutdown of the runtime, waiting for active tasks to complete within a configured timeout. |
health_check | Asynchronously returns a HealthStatus object containing metrics about the runtime's state, such as active and processed task counts. |
config | Returns a reference to the runtime's current RuntimeConfig. |
Sources: apps/runtime/crates/core/src/executor/mod.rs:17-43
Implementation Diagram
The following diagram shows the Runtime trait and its concrete implementations.
Runtime Implementations
Tokio Runtime
The TokioRuntime is the default and most feature-rich implementation. It is built on the tokio crate, a widely-used, multi-threaded runtime for asynchronous applications in Rust. It provides robust task scheduling, I/O handling, and concurrency control.
- Concurrency Limiting: It uses a
tokio::sync::Semaphoreto limit the number of concurrently executing tasks, based on themax_concurrent_tasksconfiguration. - Statistics: It tracks the total number of processed tasks, active tasks, and errors.
- Priority: The
spawn_with_prioritymethod is implemented but currently delegates to the standardspawnmethod, meaning priority is not yet utilized.
Sources: apps/runtime/crates/core/src/executor/tokio.rs:19-106
The task spawning flow includes acquiring a semaphore permit before execution.
Fiber (May) Runtime
The FiberRuntime is a lightweight alternative based on the may crate, which uses fibers (or green threads). This can be beneficial for workloads with a very high number of tasks that are mostly I/O-bound, as it can reduce context-switching overhead compared to OS threads.
- Simplicity: The current implementation is simpler than
TokioRuntime. It does not implement concurrency limiting via a semaphore. - Statistics: It tracks the total number of processed tasks, active tasks, and errors, similar to the Tokio implementation.
- Priority: Like the Tokio runtime,
spawn_with_priorityis implemented but does not currently act on the priority value.
Sources: apps/runtime/crates/core/src/executor/fiber.rs:15-60, apps/runtime/crates/core/Cargo.toml:13
Configuration
Both runtimes are configured using the RuntimeConfig struct. An instance of this configuration can be passed to the runtime's with_config method.
Sources: apps/runtime/crates/core/src/executor/mod.rs:46-54, apps/runtime/crates/core/examples/improved.rs:16-20
RuntimeConfig Options
| Field | Type | Default Value | Description |
|---|---|---|---|
max_concurrent_tasks | usize | 1000 | The maximum number of tasks allowed to run concurrently (used by TokioRuntime). |
shutdown_timeout | Duration | 30 seconds | The maximum time to wait for tasks to finish during a graceful shutdown. |
health_check_interval | Duration | 5 seconds | The interval at which health checks should be performed. |
Sources: apps/runtime/crates/core/src/executor/mod.rs:46-54, README.md:144-148
Example Configuration
A TokioRuntime can be initialized with a custom configuration as shown in the example below:
// Source: apps/runtime/crates/core/examples/improved.rs:16-21
let runtime_config = kodus_core::executor::RuntimeConfig {
max_concurrent_tasks: config.runtime.max_concurrent_tasks,
shutdown_timeout: Duration::from_secs(config.runtime.shutdown_timeout_secs),
health_check_interval: Duration::from_secs(config.runtime.health_check_interval_secs),
};
let runtime = TokioRuntime::new()?
.with_config(runtime_config);
Health Monitoring
The Runtime trait provides a unified health_check method that returns a HealthStatus struct. This allows for consistent monitoring regardless of the underlying implementation.
Sources: apps/runtime/crates/core/src/executor/mod.rs:38-40, apps/runtime/crates/core/src/executor/mod.rs:57-65
HealthStatus Fields
| Field | Type | Description |
|---|---|---|
is_healthy | bool | A boolean flag indicating the runtime's health. |
active_tasks | usize | The number of tasks currently running. |
total_tasks_processed | u64 | The total number of tasks completed since startup. |
error_count | u64 | The total number of tasks that resulted in an error. |
Sources: apps/runtime/crates/core/src/executor/mod.rs:57-65
A test case confirms that the TokioRuntime correctly tracks processed and active tasks. After spawning and awaiting 10 tasks, the health check reports 0 active tasks and 10 total processed tasks.
Sources: apps/runtime/crates/core/tests/executor.rs:5-24
Feature Selection
The choice between the Tokio and May (fiber) runtimes is controlled by Cargo features in the kodus-core crate.
async-runtime: Enables theTokioRuntimeby adding thetokiodependency. This is part of thedefaultfeature set.fiber: Enables theFiberRuntimeby adding themaydependency.
# Source: apps/runtime/crates/core/Cargo.toml:7-14
[features]
default = ["async-runtime"]
async-runtime = ["dep:tokio"]
fiber = ["dep:may"]
# ...
[dependencies]
tokio = { workspace = true, optional = true }
may = { workspace = true, optional = true }
# ...
This setup allows for compiling the kodus-runtime with only the desired executor, optimizing the final binary.
Summary
The executor model in Kodus Runtime is a powerful abstraction that decouples task management from specific asynchronous backends. It provides a choice between the production-ready, multi-threaded Tokio runtime and a lightweight May fiber-based runtime. This flexibility is managed through a common Runtime trait, a shared configuration structure, and compile-time feature flags, enabling developers to select the optimal execution strategy for their specific use case while maintaining a consistent API for task spawning and health monitoring.