kx-cron (0.1.3)

Published 2026-01-14 17:48:21 +08:00 by caisin

Installation

[registry]
default = "gitea"

[registries.gitea]
index = "sparse+" # Sparse index
# index = "" # Git

[net]
git-fetch-with-cli = true
cargo add kx-cron@0.1.3

About this package

KX-Cron

A robust, flexible, and high-performance cron scheduler for Rust applications.

Crates.io Documentation License

🚀 Features

  • Robust Scheduling: Full cron expression support with timezone awareness
  • Error Handling: Comprehensive error types with detailed messages
  • Timeout & Retry: Built-in timeout handling and configurable retry logic
  • Async & Sync: Support for both async and sync task functions
  • Parallel Control: Configure whether tasks can run in parallel with themselves
  • Graceful Shutdown: Clean task termination with proper resource cleanup
  • Builder Pattern: Intuitive API for task configuration
  • Memory Safe: No memory leaks or resource conflicts
  • Thread Safe: Full concurrent access support

📦 Installation

Add this to your Cargo.toml:

[dependencies]
kx-cron = "0.1"
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"

🏃 Quick Start

use kx_cron::prelude::*;
use std::time::Duration;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create scheduler
    let mut scheduler = CronScheduler::new();

    // Schedule a task to run every 30 seconds
    let task_id = scheduler.schedule(
        schedules::every_seconds(30)?
            .name("heartbeat")
            .timeout(Duration::from_secs(5))?
            .build(),
        || async {
            println!("Heartbeat!");
            Ok(())
        }
    ).await?;

    // Let it run
    tokio::time::sleep(Duration::from_secs(120)).await;

    // Graceful shutdown
    scheduler.shutdown().await?;
    Ok(())
}

📚 Examples

Basic Task Scheduling

use kx_cron::prelude::*;
use std::sync::{Arc, atomic::{AtomicU32, Ordering}};

let mut scheduler = CronScheduler::new();
let counter = Arc::new(AtomicU32::new(0));
let counter_clone = Arc::clone(&counter);

// Schedule every 10 seconds
let task_id = scheduler.schedule(
    schedules::every_seconds(10)?.name("counter").build(),
    move || {
        let counter = Arc::clone(&counter_clone);
        async move {
            let count = counter.fetch_add(1, Ordering::SeqCst) + 1;
            println!("Execution #{}", count);
            Ok(())
        }
    }
).await?;

Advanced Configuration

use kx_cron::prelude::*;
use std::time::Duration;

let task_id = scheduler.schedule(
    TaskBuilder::new()
        .name("complex_task")
        .schedule_str("0 */15 * * * *")? // Every 15 minutes
        .timeout(Duration::from_secs(300))? // 5 minute timeout
        .max_retries(3)? // Retry up to 3 times
        .retry_delay(Duration::from_secs(30))? // Wait 30s between retries
        .parallelizable(false) // Don't run in parallel with itself
        .build(),
    || async {
        // Your complex task here
        heavy_computation().await?;
        Ok(())
    }
).await?;

Sync Functions

// Schedule a synchronous function
let task_id = scheduler.schedule_sync(
    schedules::daily_at(3, 0)? // 3:00 AM daily
        .name("daily_backup")
        .build(),
    || {
        // Synchronous backup operation
        perform_backup()?;
        cleanup_old_files()?;
        Ok(())
    }
).await?;

Schedule Builders

// Predefined schedule builders
schedules::every_seconds(30)?    // Every 30 seconds
schedules::every_minutes(15)?    // Every 15 minutes  
schedules::every_hours(2)?       // Every 2 hours
schedules::daily_at(9, 30)?      // Daily at 9:30 AM
schedules::weekly_on(1, 8, 0)?   // Mondays at 8:00 AM
schedules::monthly_on(1, 0, 0)?  // 1st of month at midnight

// Custom cron expressions
TaskBuilder::new()
    .schedule_str("0 0 12 * * MON-FRI")? // Weekdays at noon
    .build()

Task Management

// Get scheduler info
let active_count = scheduler.active_task_count()?;
let tasks = scheduler.list_tasks()?;

for task in tasks {
    println!("Task {}: '{}' (running: {})", 
             task.id, task.name, task.is_running);
}

// Cancel specific task
let cancelled = scheduler.cancel_task(task_id)?;

// Graceful shutdown with timeout
scheduler.shutdown_with_timeout(Duration::from_secs(30)).await?;

Error Handling

use kx_cron::{CronError, Result};

// Handle different error types
match scheduler.schedule(config, task_fn).await {
    Ok(task_id) => println!("Task scheduled: {}", task_id),
    Err(CronError::InvalidExpression { expression, .. }) => {
        eprintln!("Invalid cron expression: {}", expression);
    }
    Err(CronError::SchedulerStopped) => {
        eprintln!("Scheduler is already stopped");
    }
    Err(e) => eprintln!("Other error: {}", e),
}

Timezone Support

use kx_cron::{set_timezone_utc, timezone::timezones};

// Set timezone globally
set_timezone_utc(8)?; // UTC+8 (Beijing)
set_timezone_utc(-5)?; // UTC-5 (EST)

// Use predefined timezones
let tz = timezones::cst_china()?; // China Standard Time

🔧 Configuration Options

TaskBuilder Methods

  • .name(name) - Set task name for logging
  • .schedule_str(cron) - Set cron expression
  • .schedule(schedule) - Set cron Schedule object
  • .timeout(duration) - Set execution timeout
  • .max_retries(n) - Set retry attempts (max 10)
  • .retry_delay(duration) - Set delay between retries
  • .parallelizable(bool) - Allow parallel execution

Predefined Schedules

  • every_seconds(1-60) - Every N seconds
  • every_minutes(1-60) - Every N minutes
  • every_hours(1-24) - Every N hours
  • daily_at(hour, minute) - Daily at specific time
  • weekly_on(day, hour, minute) - Weekly (1=Monday, 7=Sunday)
  • monthly_on(day, hour, minute) - Monthly on specific day

🚨 Error Types

pub enum CronError {
    InvalidExpression { expression: String, source: Error },
    Timeout { task_id: u64, timeout_seconds: u64 },
    TaskNotFound { task_id: u64 },
    TaskExecutionFailed { task_id: u64, source: anyhow::Error },
    SchedulerStopped,
    TimezoneError { message: String },
    SpawnFailed { task_id: u64, source: tokio::task::JoinError },
    LockPoisoned { message: String },
    InvalidConfiguration { field: String, value: String, reason: String },
}

Performance

  • Zero-cost abstractions - No runtime overhead when not using features
  • Efficient scheduling - Uses tokio's async runtime for optimal performance
  • Memory efficient - Minimal memory footprint with proper cleanup
  • Scalable - Handle hundreds of concurrent tasks

🛡️ Safety

  • Memory safe - No unsafe code, prevents memory leaks
  • Thread safe - All operations are thread-safe
  • Panic safe - Isolated task panics don't affect scheduler
  • Resource cleanup - Proper cleanup on shutdown

📖 Cron Expression Format

Standard cron format with seconds:

┌───────────── second (0 - 59)
│ ┌───────────── minute (0 - 59)  
│ │ ┌───────────── hour (0 - 23)
│ │ │ ┌───────────── day of month (1 - 31)
│ │ │ │ ┌───────────── month (1 - 12)
│ │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *

Special Values

  • * - Any value
  • */n - Every n units
  • n-m - Range from n to m
  • n,m,o - Specific values n, m, and o
  • @yearly - Once a year (0 0 0 1 1 *)
  • @monthly - Once a month (0 0 0 1 * *)
  • @weekly - Once a week (0 0 0 * * 0)
  • @daily - Once a day (0 0 0 * * *)
  • @hourly - Once an hour (0 0 * * * *)

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📝 License

This project is licensed under the MIT License - see the LICENSE file for details.

Dependencies

ID Version
anyhow ^1
chrono ^0.4
cron ^0.15.0
serde ^1
serde_json ^1.0.140
thiserror ^2
tokio ^1
tracing ^0.1
tracing-test ^0.2
Details
Cargo
2026-01-14 17:48:21 +08:00
3
Caisin
Caisin
29 KiB
Assets (1)
Versions (1) View all
0.1.3 2026-01-14