Task Scheduler in Rust: Building a Reliable Job Scheduler

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Task Scheduler in Rust: From a Simple Timer to an Industrial Job Scheduler



A job scheduler is one of the key components of any serious application. In Rust, you can build a system that executes with millisecond precision, consumes minimal memory, and runs without failures for years. In this article, we will break down how to create a task scheduler in Rust, using both standard tools and popular crates.



Why Write a Scheduler in Rust?



Rust offers a unique combination of performance and safety. A task scheduler in Rust:



  • Guarantees the absence of data races — the compiler checks this at compile time.
  • Runs without a garbage collector — predictable task execution latency.
  • Supports both asynchronous and multithreaded execution.
  • Has a minimal memory footprint — you can run thousands of tasks.


Simplest Scheduler with std::thread::sleep



Let's start with a basic example — cyclic execution of a task every N seconds:



use std::thread;use std::time::Duration;

fn main() { let interval = Duration::from_secs(5); loop { println!("[{}] Executing task...", chrono::Local::now().format("%H:%M:%S")); // Your task code here thread::sleep(interval); }}


This approach is simple but inefficient: it blocks the current thread, and there is no way to run multiple tasks in parallel.



Async Scheduler with tokio



For real projects, use tokio — an async runtime that allows you to run thousands of tasks in a single thread.



use tokio::time::{interval, Duration};

#[tokio::main]async fn main() { let mut timer = interval(Duration::from_secs(10)); println!("Scheduler started. The task will run every 10 seconds."); loop { timer.tick().await; println!("[{}] Executing task...", chrono::Local::now().format("%H:%M:%S")); // Async task: for example, an API request do_work().await; }}

async fn do_work() { // Simulating useful work tokio::time::sleep(Duration::from_millis(500)).await; println!("Task completed.");}


Advantages: does not block the thread, you can run hundreds of such schedulers in parallel.



CRON-like Scheduling with the cron Crate



If you need to define complex schedules (like in Linux cron), use the cron crate:



use cron::Schedule;use chrono::Utc;use std::str::FromStr;

fn main() { // Every minute at 30 seconds let expression = "30 * * * * *"; let schedule = Schedule::from_str(expression).unwrap(); println!("Next 5 runs:"); for datetime in schedule.upcoming(Utc).take(5) { println!(" {}", datetime); }}


Here is a more complete example with actual execution:



use cron::Schedule;use chrono::{Utc, Local};use std::thread;use std::time::Duration;use std::str::FromStr;

fn main() { // Every 15 seconds let expression = "0/15 * * * * *"; let schedule = Schedule::from_str(expression).unwrap(); loop { let now = Utc::now(); if let Some(next) = schedule.upcoming(Utc).next() { let delay = next - now; let millis = delay.num_milliseconds().max(0) as u64; thread::sleep(Duration::from_millis(millis)); println!("[{}] Scheduled task!", Local::now().format("%H:%M:%S")); // Task execution } else { thread::sleep(Duration::from_secs(1)); } }}


Industrial Scheduler with Multithreading



For serious projects, create a Scheduler struct

Recommendations