A Resilient, High-Performance Task Scheduler for Rust
tokio::spawngives you fire-and-forget concurrency — no priority, no backpressure, no structured shutdown. CPU-bound work blocks the executor, starving latency-sensitive tasks. A task scheduler without priority awareness means a background file-index can stall a keystroke."Every CPU core stays busy. High-priority tasks always pre-empt background work. Shutdown drains gracefully, never drops a task in flight."
Echo is a bounded work-stealing task scheduler for Rust, designed as the
core execution engine for application backends like Mountain. It provides
structured concurrency with priority-based task scheduling across a Tokio
thread pool, using lock-free crossbeam-deque queues to maximize CPU
utilization without central bottlenecks.
tokio::spawn is great for I/O-bound work, but CPU-bound tasks — parsing,
diffing, indexing — block the executor. Echo provides priority levels so
latency-sensitive operations always take precedence, work-stealing so idle
workers pick up tasks from busy ones, and structured shutdown so no task is
lost when the system drains.
Echo is engineered to:
- Prioritize Critical Work —
High-priority tasks (UI responses, keystroke processing) always execute beforeNormalandLow-priority background work, ensuring consistent perceived performance. - Maximize CPU Utilization — Lock-free work-stealing via
crossbeam-dequeeliminates scheduling bottlenecks. Idle workers automatically steal from busy ones, keeping every core productive. - Provide Structured Concurrency — Unlike fire-and-forget
tokio::spawn, the scheduler manages a supervised pool of workers with graceful startup and shutdown. TheDropguard ensures clean teardown even on panic. - Maintain a Decoupled Architecture — The generic
Queuemodule provides core work-stealing logic as a standalone library. TheSchedulerlayer adds priority scheduling, worker management, and a fluent builder API.
Work-Stealing Scheduler — Implements a priority-aware work-stealing
algorithm using crossbeam-deque to efficiently distribute tasks across a
pool of worker threads. Idle workers automatically steal from busy peers'
local deques and the global injector queue, ensuring no core sits idle while
work is available.
Task Prioritization — Supports submitting tasks with High, Normal, or
Low priority levels. High-priority tasks are always dequeued first from
local and global deques, ensuring that latency-sensitive operations respond
immediately while background work yields gracefully.
Fluent Builder API — The SchedulerBuilder provides a clean, chainable
configuration interface. It defaults to the number of logical CPU cores with a
minimum of two workers, and supports explicit worker count overrides and named
queue configuration for future extensibility.
Graceful Shutdown — The Stop() method signals all worker threads to
terminate and waits for each to complete its current task before joining. An
automatic Drop guard ensures workers are signaled to stop even if the
scheduler is dropped without an explicit shutdown call.
Lock-Free Performance — All queue operations use crossbeam-deque's
lock-free Injector and Worker primitives. The global injector queue
handles remote submissions, while each worker maintains local FIFO deques for
cache-friendly task processing.
Decoupled Queue Library — The generic Queue module provides the core
work-stealing logic as a standalone library, independent of any specific
scheduler implementation. The StealingQueue<TTask> accepts any type
implementing the Prioritized trait, making it reusable across projects.
| Principle | Description | Key Components |
|---|---|---|
| Work Stealing | Use lock-free data structures (crossbeam-deque) with random victim selection to keep all cores productive. Idle workers pull from peer local deques and the global injector queue. |
Queue::StealingQueue, Scheduler::Worker |
| Priority Scheduling | Three priority tiers (High, Normal, Low) determine deque ordering. The Prioritized trait decouples priority assignment from the queue implementation. |
Task::Priority, Queue::StealingQueue::Prioritized |
| Structured Concurrency | Manage all asynchronous operations within a supervised pool of workers with explicit startup and graceful shutdown. The Drop guard guarantees clean teardown. |
Scheduler::Scheduler, Scheduler::SchedulerBuilder |
| Decoupling | Separate the generic queueing logic from the application-specific scheduler. The scheduler uses the queue to run tasks; the queue knows nothing about Tokio workers or Mountain. |
Queue::StealingQueue<TTask>, Task::Task, Scheduler::Scheduler |
| Composability | A simple Submit API accepts any Future<Output = ()> + Send, making it easy to integrate with any asynchronous Rust codebase. |
Task::Task, Scheduler::Scheduler::Submit |
graph LR
classDef common fill:#d4f5d4,stroke:#27ae60,stroke-width:1px,stroke-dasharray:5 5,color:#0a3a0a;
classDef mountain fill:#f0d0ff,stroke:#9b59b6,stroke-width:2px,color:#2c0050;
classDef echo fill:#fffde0,stroke:#f0b429,stroke-width:2px,color:#4a3500;
classDef worker fill:#ffe0f0,stroke:#c0396a,stroke-width:1px,color:#4a0020;
subgraph COMMON["Common - Abstract Core"]
ActionEffect["ActionEffect ⚡ operation as value"]:::common
Prioritized["Prioritized trait 🏷️ High / Normal / Low"]:::common
end
subgraph MOUNTAIN["Mountain ⛰️ - Application Logic"]
Track["Track/ 🎯 Request Dispatcher"]:::mountain
AppRunTime["ApplicationRunTime ⏱️ runtime executor"]:::mountain
MountainEnv["Environment/ Providers 🔧 concrete service impls"]:::mountain
Track --> AppRunTime
end
subgraph ECHO["Echo 📣 - Work-Stealing Scheduler"]
direction TB
subgraph SCHEDULER["Scheduler/"]
SchedBuilder["SchedulerBuilder.rs ⚙️ fluent config, defaults to num_cpus"]:::echo
SchedCore["Scheduler.rs 🎛️ Submit API + graceful Stop"]:::echo
Workers["Worker.rs 🏃 Tokio threads, steal-on-idle"]:::worker
SchedBuilder --> SchedCore
SchedCore --> Workers
end
subgraph QUEUE["Queue/"]
StealQ["StealingQueue.rs 🔒 crossbeam-deque, lock-free"]:::echo
end
subgraph TASK["Task/"]
TaskDef["Task.rs + Priority.rs 📦 Future wrapper + priority level"]:::echo
end
Workers -- steals from --> StealQ
SchedCore -- enqueues --> StealQ
TaskDef -.implements.-> Prioritized
end
AppRunTime -- creates Future from --> ActionEffect
AppRunTime -- Submit Future --> SchedCore
Workers -- executes using --> MountainEnv
Connection paths:
| Path | Mechanism | Use Case |
|---|---|---|
Mountain → Echo |
Submit(Future, Priority) |
Dispatch ActionEffect-derived futures to the worker pool |
| Worker → Peer Worker | crossbeam-deque steal |
Idle workers pull tasks from busy workers' local deques |
| Worker → Injector Queue | crossbeam-deque steal |
Workers fall back to the global injector when local and peer deques are empty |
| Anything → Echo | Submit(Future, Priority) |
Any application code can submit any Future<Output = ()> + Send |
| Component | Path | Description |
|---|---|---|
| Library Entry | Source/Library.rs |
Crate root, declares all modules with doc comments |
| Scheduler | Source/Scheduler/Scheduler.rs |
Main runtime: Submit, Stop, worker pool lifecycle |
| Scheduler Builder | Source/Scheduler/SchedulerBuilder.rs |
Fluent builder: worker count, queue configuration, defaults to num_cpus |
| Worker | Source/Scheduler/Worker.rs |
Per-thread execution loop with steal-on-idle logic |
| StealingQueue | Source/Queue/StealingQueue.rs |
Generic lock-free work-stealing queue wrapping crossbeam-deque |
| Queue Module | Source/Queue/mod.rs |
Module declaration for the Queue subsystem |
| Task | Source/Task/Task.rs |
Schedulable unit: boxed Future + priority metadata |
| Priority | Source/Task/Priority.rs |
High, Normal, Low priority enum |
| Task Module | Source/Task/mod.rs |
Module declaration for the Task subsystem |
Element/Echo/
├── Source/
│ ├── Library.rs # Crate root (rlib), module declarations
│ ├── Queue/ # Generic work-stealing queue library
│ │ ├── mod.rs # Module re-exports
│ │ └── StealingQueue.rs # Lock-free, priority-aware stealing deque
│ ├── Scheduler/ # Scheduler runtime and worker pool
│ │ ├── mod.rs # Module re-exports
│ │ ├── Scheduler.rs # Main scheduler: Submit + Stop lifecycle
│ │ ├── SchedulerBuilder.rs # Fluent builder with worker count config
│ │ └── Worker.rs # Per-thread Tokio worker with steal loop
│ └── Task/ # Task definition and priority
│ ├── mod.rs # Module re-exports
│ ├── Task.rs # Schedulable unit (Future + Priority)
│ └── Priority.rs # High / Normal / Low enum
└── Documentation/
└── GitHub/
├── Architecture.md # Internal module structure and data flow
└── DeepDive.md # In-depth technical details
Echo serves as the core execution engine for Mountain, the native
Rust/Tauri backend of the Land Code Editor. It integrates seamlessly with
the ActionEffect pattern from the Common crate, executing composed
asynchronous workflows across a priority-aware worker pool.
The Mountain runtime submits futures derived from ActionEffect values to
the Echo scheduler, which distributes them across its workers alongside the
concrete Environment provider implementations. High-priority UI operations
— keystroke processing, command execution, diagnostics — always pre-empt
background work like file indexing and syntax analysis.
| Layer | Role | Integration with Echo |
|---|---|---|
| Mountain | Application backend (Tauri native shell) |
Submits ActionEffect-derived futures to Echo |
| Echo | Work-stealing task scheduler | Distributes work across Tokio workers with priority ordering |
| Common | Abstract traits and shared types | Provides Prioritized trait and ActionEffect pattern |
- Rust 1.75 or later
- A
Tokioruntime (Echo usestokiointernally)
Add Echo to your project via the Land workspace:
[dependencies]
Echo = { git = "https://github.com/CodeEditorLand/Echo.git", branch = "Current" }The crate depends on tokio, crossbeam-deque, rand, log, num_cpus,
and Common from the Land workspace. All dependencies are resolved through
the workspace Cargo.toml configuration.
First, create and start the scheduler when your application initializes. The builder defaults to the number of logical CPU cores, with a minimum of two workers to ensure work-stealing is viable:
use std::sync::Arc;
use Echo::Scheduler::SchedulerBuilder;
use Echo::Task::Priority;
let Scheduler = Arc::new(SchedulerBuilder::Create().WithWorkerCount(8).Build());Submit asynchronous tasks from anywhere in your application using the scheduler instance. Tasks are queued by priority and executed by the next available worker:
let MyTask = async {
println!("This is running on an Echo worker thread!");
// ... perform some work ...
};
// Submit the task with a desired priority
Scheduler.Submit(MyTask, Priority::Normal);
// Another example with high priority
Scheduler.Submit(async { /* critical work */ }, Priority::High);Before your application exits, ensure a clean shutdown of all worker threads.
The Stop() method drains the queue and waits for in-flight tasks to
complete:
// Note: Arc::try_unwrap requires the Arc to have only one strong reference.
if let Ok(mut Scheduler) = Arc::try_unwrap(Scheduler) {
Scheduler.Stop().await;
}- Architecture Overview — Land system architecture
- Deep Dive — In-depth technical details of the work-stealing algorithm
- Land Documentation — Complete documentation index
Mountain— Primary consumer of Echo, nativeTauridesktop shellCommon— Abstract traits andActionEffectsystem- Why Rust
- Contribution Guide
CHANGELOG.md— History of changes specific to Echo
Echo is a core element of the Land ecosystem. This project is funded through NGI0 Commons Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet program, under grant agreement No 101135429.
The project is operated by PlayForm, based in Sofia, Bulgaria. PlayForm acts as the open-source steward for Code Editor Land under the NGI0 Commons Fund grant.
|
|
|
|
|