graphile_worker_crontab_runner 0.7.9

Crontab runner package for graphile worker, a high performance Rust/PostgreSQL job queue
Documentation
use chrono::{DateTime, Local};
use graphile_worker_runtime as runtime;
use std::future::Future;

pub trait Clock: Send + Sync {
    fn now(&self) -> DateTime<Local>;

    fn sleep_until(&self, datetime: DateTime<Local>) -> impl Future<Output = ()> + Send;
}

#[derive(Clone, Copy, Default)]
pub struct SystemClock;

impl Clock for SystemClock {
    fn now(&self) -> DateTime<Local> {
        Local::now()
    }

    async fn sleep_until(&self, datetime: DateTime<Local>) {
        let dur = datetime - Local::now();
        let Ok(std_dur) = dur.to_std() else { return };
        runtime::sleep(std_dur).await;
    }
}

pub mod mock {
    use super::*;
    use std::sync::{Arc, Mutex};

    pub struct MockClock {
        current_time: Arc<Mutex<DateTime<Local>>>,
        wake_notify: Arc<runtime::Notify>,
    }

    impl MockClock {
        pub fn new(initial_time: DateTime<Local>) -> Self {
            Self {
                current_time: Arc::new(Mutex::new(initial_time)),
                wake_notify: Arc::new(runtime::Notify::new()),
            }
        }

        pub fn set_time(&self, time: DateTime<Local>) {
            *self.current_time.lock().unwrap() = time;
            self.wake_notify.notify_waiters();
        }

        pub fn advance(&self, duration: chrono::Duration) {
            let mut time = self.current_time.lock().unwrap();
            *time += duration;
            drop(time);
            self.wake_notify.notify_waiters();
        }
    }

    impl Clock for MockClock {
        fn now(&self) -> DateTime<Local> {
            *self.current_time.lock().unwrap()
        }

        async fn sleep_until(&self, datetime: DateTime<Local>) {
            loop {
                let now = self.now();
                if now >= datetime {
                    return;
                }
                self.wake_notify.notified().await;
            }
        }
    }

    impl Clock for Arc<MockClock> {
        fn now(&self) -> DateTime<Local> {
            MockClock::now(self)
        }

        async fn sleep_until(&self, datetime: DateTime<Local>) {
            MockClock::sleep_until(self, datetime).await
        }
    }
}