Planificateur de tâches en Rust : création d'un job scheduler fiable

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Planificateur de tâches en Rust : du simple minuteur au job scheduler industriel



Un planificateur de tâches (job scheduler) est l'un des composants clés de toute application sérieuse. Avec Rust, vous pouvez construire un système qui s'exécutera avec une précision à la milliseconde, consommera un minimum de mémoire et fonctionnera sans panne pendant des années. Dans cet article, nous allons voir comment créer un planificateur de tâches en Rust, en utilisant à la fois les outils standards et les crates populaires.



Pourquoi écrire un planificateur en Rust ?



Rust offre une combinaison unique de performance et de sécurité. Un planificateur de tâches en Rust :



  • Garantit l'absence de courses de données (data races) — le compilateur le vérifie à la compilation.
  • Fonctionne sans ramasse-miettes (garbage collector) — latence d'exécution des tâches prévisible.
  • Prend en charge à la fois l'exécution asynchrone et multithreadée.
  • A une empreinte mémoire minimale — vous pouvez exécuter des milliers de tâches.


Planificateur le plus simple avec std::thread::sleep



Commençons par un exemple de base — l'exécution cyclique d'une tâche toutes les N secondes :



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

fn main() { let interval = Duration::from_secs(5); loop { println!("[{}] Exécution de la tâche...", chrono::Local::now().format("%H:%M:%S")); // Votre code de tâche ici thread::sleep(interval); }}


Cette approche est simple mais inefficace : elle bloque le thread actuel et ne permet pas d'exécuter plusieurs tâches en parallèle.



Planificateur asynchrone avec tokio



Pour les projets réels, utilisez tokio — un runtime asynchrone qui permet d'exécuter des milliers de tâches dans un seul thread.



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

#[tokio::main]async fn main() { let mut timer = interval(Duration::from_secs(10)); println!("Planificateur démarré. La tâche s'exécutera toutes les 10 secondes."); loop { timer.tick().await; println!("[{}] Exécution de la tâche...", chrono::Local::now().format("%H:%M:%S")); // Tâche asynchrone : par exemple, une requête API do_work().await; }}

async fn do_work() { // Simulation d'un travail utile tokio::time::sleep(Duration::from_millis(500)).await; println!("Tâche terminée.");}


Avantages : ne bloque pas le thread, permet d'exécuter des centaines de ces planificateurs en parallèle.



Ordonnancement de type CRON avec la crate cron



Si vous avez besoin de définir des ordonnancements complexes (comme dans Linux cron), utilisez la crate cron :



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

fn main() { // Chaque minute à 30 secondes let expression = "30 * * * * *"; let schedule = Schedule::from_str(expression).unwrap(); println!("Les 5 prochaines exécutions :"); for datetime in schedule.upcoming(Utc).take(5) { println!(" {}", datetime); }}


Voici un exemple plus complet avec une exécution réelle :



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

fn main() { // Toutes les 15 secondes 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!("[{}] Tâche planifiée !", Local::now().format("%H:%M:%S")); // Exécution de la tâche } else { thread::sleep(Duration::from_secs(1)); } }}


Planificateur industriel avec multithreading



Pour les projets sérieux, créez une structure Scheduler

Recommendations