easycron 0.1.2

rust cron library
Documentation
use anyhow::Result;
use chrono::Local;
use cron::Schedule;
use nanoid::nanoid;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use tokio::task::JoinHandle;

pub type JobId = String;

#[derive(Clone)]
struct JobFunc(Arc<dyn Fn() + Send + Sync>);

#[derive(Clone)]
pub struct Job {
    pub id: JobId,
    pub name: String,
    pub schedule: Schedule,
    func: JobFunc,
    h: Option<Arc<JoinHandle<()>>>,
}

impl Job {
    pub fn new<F>(name: &str, expr: &str, func: F) -> Result<Self>
    where
        F: Fn() + Send + Sync + 'static,
    {
        Self::new_with_id(nanoid!().as_str(), name, expr, func)
    }

    pub fn new_with_id<F>(id: &str, name: &str, expr: &str, func: F) -> Result<Self>
    where
        F: Fn() + Send + Sync + 'static,
    {
        Ok(Self {
            id: id.to_string(),
            name: name.to_string(),
            schedule: Schedule::from_str(expr)?,
            func: JobFunc(Arc::new(func)),
            h: Default::default(),
        })
    }

    pub async fn run(&mut self) {
        let schedule = self.schedule.clone();
        let func = self.func.clone();
        self.h = Some(Arc::new(tokio::spawn(async move {
            for upcoming in schedule.upcoming(Local) {
                let dur = (upcoming - Local::now()).num_milliseconds();
                tokio::time::sleep(Duration::from_millis(dur as u64)).await;
                func.0();
            }
        })));
    }

    pub fn stop(&self) {
        if let Some(h) = &self.h {
            h.abort();
        }
    }
}