Планировщик задач Rust: обзор библиотек и примеры кода

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Планировщик задач Rust: полное руководство для разработчиков

Планировщики задач — неотъемлемая часть современной разработки. Они позволяют автоматизировать выполнение рутинных операций: периодическую очистку кэша, отправку уведомлений, синхронизацию данных и многое другое. В экосистеме Rust существует несколько мощных библиотек для реализации планировщиков. В этой статье мы разберём три основных подхода: cron, tokio-cron-scheduler и job_scheduler.

1. Базовый планировщик с библиотекой cron

Библиотека cron предоставляет минималистичный функционал для парсинга cron-выражений и вычисления времени следующего запуска. Она не содержит встроенного цикла выполнения, поэтому её часто комбинируют с tokio или std::thread.

Установка:

[dependencies]
cron = "0.12"
chrono = "0.4"
tokio = { version = "1", features = ["full"] }

Пример простого планировщика:

use cron::Schedule;
use chrono::Utc;
use std::str::FromStr;
use std::thread;
use std::time::Duration;

fn main() {
    // Каждую минуту
    let expression = "0 * * * * *";
    let schedule = Schedule::from_str(expression).unwrap();

    loop {
        let now = Utc::now();
        if let Some(next) = schedule.upcoming(Utc).next() {
            let duration = next - now;
            if duration.num_seconds() > 0 {
                thread::sleep(Duration::from_secs(duration.num_seconds() as u64));
            }
            println!("[{}] Задача выполнена!", Utc::now());
        }
    }
}

Этот подход даёт полный контроль, но требует ручного управления циклом. Подходит для простых сценариев.

2. Асинхронный планировщик tokio-cron-scheduler

Для современных асинхронных приложений на базе tokio идеально подходит библиотека tokio-cron-scheduler. Она предоставляет готовый планировщик с поддержкой сложных cron-расписаний, джобов с идентификаторами и обработчиков ошибок.

Установка:

[dependencies]
tokio-cron-scheduler = "0.10"
tokio = { version = "1", features = ["full"] }

Пример с двумя задачами:

use tokio_cron_scheduler::{Job, JobScheduler};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let sched = JobScheduler::new().await?;

    // Задача 1: каждые 5 секунд
    let job1 = Job::new_async("*/5 * * * * *", |_uuid, _lock| {
        Box::pin(async move {
            println!("[Job1] Выполнено в {:?}", std::time::SystemTime::now());
        })
    })?;

    // Задача 2: каждую минуту
    let job2 = Job::new_async("0 * * * * *", |_uuid, _lock| {
        Box::pin(async move {
            println!("[Job2] Минутная задача");
        })
    })?;

    sched.add(job1).await?;
    sched.add(job2).await?;
    sched.start().await?;

    // Держим приложение запущенным
    tokio::signal::ctrl_c().await?;
    println!("Планировщик остановлен");
    Ok(())
}

Преимущества: автоматическое управление временем, поддержка удаления/паузы задач, асинхронное выполнение без блокировок.

3. Простой планировщик job_scheduler

Библиотека job_scheduler ориентирована на максимальную простоту. Она не требует асинхронного рантайма и подходит для консольных утилит или встраивания в уже существующие синхронные проекты.

Установка:

[dependencies]
job_scheduler = "1.2"
chrono = "0.4"

Пример:

use job_scheduler::{Job, JobScheduler};
use std::time::Duration;

fn main() {
    let mut sched = JobScheduler::new();

    sched.add(Job::new("1/10 * * * * *".parse().unwrap(), || {
        println!("Выполнение задачи каждые 10 секунд");
    }));

    loop {
        sched.tick();
        std::thread::sleep(Duration::from_millis(500));
    }
}

Этот планировщик крайне лёгкий, но не поддерживает асинхронные замыкания и сложные сценарии отмены задач.

Сравнительная таблица

  • cron — минималистичный парсер, полный контроль

Рекомендаций