### Scheduler Usage Examples Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.Scheduler.html Demonstrates various ways to create and configure a Scheduler, add jobs with different intervals and times, and run them. ```rust // Scheduler, trait for .seconds(), .minutes(), etc., and trait with job scheduling methods use clokwerk::{Scheduler, TimeUnits, Job}; // Import week days and WeekDay use clokwerk::Interval::*; use std::thread; use std::time::Duration; // Create a new scheduler let mut scheduler = Scheduler::new(); // or a scheduler with a given timezone let mut scheduler = Scheduler::with_tz(chrono::Utc); // Add some tasks to it scheduler .every(10.minutes()) .plus(30.seconds()) .run(|| println!("Periodic task")); scheduler .every(1.day()) .at("3:20 pm") .run(|| println!("Daily task")); scheduler .every(Wednesday) .at("14:20:17") .run(|| println!("Weekly task")); scheduler .every(Tuesday) .at("14:20:17") .and_every(Thursday) .at("15:00") .run(|| println!("Biweekly task")); scheduler .every(Weekday) .run(|| println!("Every weekday at midnight")); scheduler .every(1.day()) .at("3:20 pm") .run(|| println!("I only run once")).once(); scheduler .every(Weekday) .at("12:00").count(10) .run(|| println!("Countdown")); scheduler .every(1.day()) .at("10:00 am") .repeating_every(30.minutes()) .times(6) .run(|| println!("I run every half hour from 10 AM to 1 PM inclusive.")); scheduler .every(1.day()) .at_time(chrono::NaiveTime::from_hms(13, 12, 14)) .run(|| println!("You can also pass chrono::NaiveTimes to `at_time`.")); // Manually run the scheduler in an event loop for _ in 1..10 { scheduler.run_pending(); thread::sleep(Duration::from_millis(10)); } // Or run it in a background thread let thread_handle = scheduler.watch_thread(Duration::from_millis(100)); // The scheduler stops when `thread_handle` is dropped, or `stop` is called thread_handle.stop(); ``` -------------------------------- ### Scheduler Usage Examples Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/scheduler.rs.html Demonstrates how to initialize a scheduler, define various task intervals, and execute tasks either manually or in a background thread. ```rust // Scheduler, trait for .seconds(), .minutes(), etc., and trait with job scheduling methods use clokwerk::{Scheduler, TimeUnits, Job}; // Import week days and WeekDay use clokwerk::Interval::*; use std::thread; use std::time::Duration; // Create a new scheduler let mut scheduler = Scheduler::new(); // or a scheduler with a given timezone let mut scheduler = Scheduler::with_tz(chrono::Utc); // Add some tasks to it scheduler .every(10.minutes()) .plus(30.seconds()) .run(|| println!("Periodic task")); scheduler .every(1.day()) .at("3:20 pm") .run(|| println!("Daily task")); scheduler .every(Wednesday) .at("14:20:17") .run(|| println!("Weekly task")); scheduler .every(Tuesday) .at("14:20:17") .and_every(Thursday) .at("15:00") .run(|| println!("Biweekly task")); scheduler .every(Weekday) .run(|| println!("Every weekday at midnight")); scheduler .every(1.day()) .at("3:20 pm") .run(|| println!("I only run once")).once(); scheduler .every(Weekday) .at("12:00").count(10) .run(|| println!("Countdown")); scheduler .every(1.day()) .at("10:00 am") .repeating_every(30.minutes()) .times(6) .run(|| println!("I run every half hour from 10 AM to 1 PM inclusive.")); scheduler .every(1.day()) .at_time(chrono::NaiveTime::from_hms(13, 12, 14)) .run(|| println!("You can also pass chrono::NaiveTimes to `at_time`.")); // Manually run the scheduler in an event loop for _ in 1..10 { scheduler.run_pending(); thread::sleep(Duration::from_millis(10)); # break; } // Or run it in a background thread let thread_handle = scheduler.watch_thread(Duration::from_millis(100)); // The scheduler stops when `thread_handle` is dropped, or `stop` is called thread_handle.stop(); ``` -------------------------------- ### Create a RunConfig from an Interval Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/intervals.rs.html Initializes a `RunConfig` with a base interval. This is the starting point for defining a schedule. ```rust pub fn from_interval(base: Interval) -> Self { RunConfig { base, adjustment: None, } } ``` -------------------------------- ### Configure Job Repetition Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html Examples demonstrating how to use repeating_every to schedule recurring tasks with specific intervals and repetition counts. ```rust let mut scheduler = Scheduler::new(); scheduler.every(Weekday) .at("7:40") .repeating_every(10.minutes()) .times(5) .run(|| hit_snooze()); ``` ```rust let mut scheduler = Scheduler::new(); scheduler.every(Weekday) .at("7:40") .and_every(Saturday) .at("9:15") .and_every(Sunday) .at("9:15") .repeating_every(10.minutes()) .times(5) .run(|| hit_snooze()); ``` ```rust let mut scheduler = Scheduler::new(); scheduler.every(1.hour()) .repeating_every(45.minutes()) .times(3) .run(|| println!("Hello")); ``` -------------------------------- ### Schedule Job with Time Offset (Example 3) Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html Demonstrates scheduling a job with a 90-minute offset from a 1-hour interval, resulting in runs at XX:30. ```rust scheduler.every(1.hour()) .plus(90.minutes()) .run(|| println!("Time to wake up!")); ``` -------------------------------- ### Running AsyncScheduler with Tokio Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/async_scheduler.rs.html Example of how to run the AsyncScheduler in a loop using tokio::spawn. This is useful for continuously checking and running pending jobs. ```rust tokio::spawn(async move { loop { scheduler.run_pending().await; tokio::time::sleep(Duration::from_millis(100)).await; } }); ``` -------------------------------- ### Example: Running Pending Jobs in a Loop Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/scheduler.rs.html Demonstrates how to continuously check and run pending jobs in a loop with a small delay. This is a common pattern for background task execution. ```rust # use clokwerk::* # use clokwerk::Interval::* use std::thread use std::time::Duration # let mut scheduler = Scheduler::new() loop { scheduler.run_pending() thread::sleep(Duration::from_millis(100)) # break } ``` -------------------------------- ### Schedule Job with Time Offset (Example 2) Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html Illustrates scheduling a job with a 30-minute offset from a 1-hour interval, resulting in runs at XX:30. ```rust scheduler.every(1.hour()) .plus(30.minutes()) .run(|| println!("Time to wake up!")); ``` -------------------------------- ### TimeUnits Usage Examples Source: https://docs.rs/clokwerk/0.4.0/clokwerk/trait.TimeUnits.html Demonstrates how to use the TimeUnits trait methods to create Interval instances. Plural and non-plural forms are interchangeable. ```rust assert_eq!(5.seconds(), Interval::Seconds(5)); assert_eq!(12.minutes(), Interval::Minutes(12)); assert_eq!(2.hours(), Interval::Hours(2)); assert_eq!(3.days(), Interval::Days(3)); assert_eq!(1.week(), Interval::Weeks(1)); ``` -------------------------------- ### Configure and Run Async Jobs Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.AsyncScheduler.html Examples showing how to configure and run different types of async jobs using the `every` method on AsyncScheduler. Includes scheduling periodic tasks, tasks at specific times, and tasks on specific weekdays. ```rust let mut scheduler = AsyncScheduler::new(); scheduler.every(10.minutes()).plus(30.seconds()).run(|| async { println!("Periodic task") }); scheduler.every(1.day()).at("3:20 pm").run(|| some_async_fn()); scheduler.every(Wednesday).at("14:20:17").run(|| Pin::from(returns_boxed_future())); scheduler.every(Weekday).run(|| returns_pinned_boxed_future()); ``` -------------------------------- ### Running AsyncScheduler with async-std Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/async_scheduler.rs.html Example of how to run the AsyncScheduler in a loop using async_std::task::spawn. This provides an alternative to tokio for managing the scheduler's execution. ```rust async_std::task::spawn(async move { loop { scheduler.run_pending().await; async_std::task::sleep(Duration::from_millis(100)).await; } }); ``` -------------------------------- ### Schedule Job with Time Offset (Example 4) Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html Shows scheduling a job with a 125-minute offset from a 1-hour interval, resulting in runs at XX:05. ```rust scheduler.every(1.hour()) .plus(125.minutes()) .run(|| println!("Time to wake up!")); ``` -------------------------------- ### Start Scheduler Watch Thread Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/scheduler.rs.html Starts a background thread that repeatedly calls `run_pending` at a specified frequency. The `ScheduleHandle` returned must be kept alive to maintain the thread; dropping it terminates the thread. ```rust # use std::sync::atomic::{AtomicBool, Ordering} # use std::sync::Arc # use std::thread # use std::time::Duration # use clokwerk::Scheduler # pub struct ScheduleHandle { stop: Arc, thread_handle: Option> } # impl Scheduler where Tz: chrono::TimeZone + Sync + Send + 'static, ::Offset: Send { pub fn watch_thread(self, frequency: Duration) -> ScheduleHandle { let stop = Arc::new(AtomicBool::new(false)); let my_stop = stop.clone(); let mut me = self; let handle = thread::spawn(move || { while !stop.load(Ordering::SeqCst) { me.run_pending(); thread::sleep(frequency); } }); ScheduleHandle { stop: my_stop, thread_handle: Some(handle), } } # } ``` -------------------------------- ### Basic AsyncScheduler Usage Example Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.AsyncScheduler.html Demonstrates scheduling various types of asynchronous tasks with AsyncScheduler, including simple async blocks, named async functions, and futures returning boxed or pinned futures. ```rust // Scheduler, trait for .seconds(), .minutes(), etc., and trait with job scheduling methods use clokwerk::{AsyncScheduler, TimeUnits, Job}; // Import week days and WeekDay use clokwerk::Interval::*; use std::time::Duration; // Create a new scheduler let mut scheduler = AsyncScheduler::new(); // Add some tasks to it scheduler .every(10.minutes()) .plus(30.seconds()) .run(|| async { println!("Simplest is just using an async block"); }); scheduler .every(1.day()) .at("3:20 pm") .run(|| some_async_fn()); scheduler .every(Wednesday) .at("14:20:17") .run(some_async_fn); scheduler .every(Tuesday) .at("14:20:17") .and_every(Thursday) .at("15:00") .run(|| std::pin::Pin::from(returns_boxed_future())); scheduler .every(Weekday) .run(|| returns_pinned_boxed_future()); scheduler .every(1.day()) .at("3:20 pm") .run(returns_pinned_boxed_future).once(); // Manually run the scheduler forever loop { scheduler.run_pending().await; tokio::time::sleep(Duration::from_millis(10)).await; } // Or spawn a task to run it forever tokio::spawn(async move { loop { scheduler.run_pending().await; tokio::time::sleep(Duration::from_millis(100)).await; } }); ``` -------------------------------- ### Start Background Watch Thread Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.Scheduler.html Launches a background thread to periodically call `run_pending()`. The `frequency` determines the sleep duration between calls. Dropping the `ScheduleHandle` gracefully stops the thread. ```rust let thread_handle = scheduler.watch_thread(Duration::from_millis(100)); ``` -------------------------------- ### Calculate Next Interval Start Time Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/intervals.rs.html Calculates the next occurrence of an interval based on a starting DateTime, handling various interval types including seconds, minutes, hours, days, weeks, specific days of the week, and weekdays. ```rust Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday => { let d = from.date(); let dow = d.weekday().num_days_from_monday() as i32; let i_dow = day_of_week(*self) as i32; let mut to_shift = if dow >= i_dow { dow - i_dow } else { 7 + dow - i_dow }; if to_shift == 0 && from.num_seconds_from_midnight() == 0 { to_shift = 7; } (from.date() - Duration::days(i64::from(to_shift))).and_hms(0, 0, 0) } Weekday => { let d = from.date(); let dow = d.weekday(); let days = match dow { Weekday::Sat => 1, Weekday::Sun => 2, _ => { if from.num_seconds_from_midnight() == 0 { 1 } else { 0 } } }; (from.date() - Duration::days(days)).and_hms(0, 0, 0) } } } } impl Interval { pub(crate) fn next_from(&self, from: &DateTime) -> DateTime { match *self { Seconds(x) | Minutes(x) | Hours(x) | Days(x) | Weeks(x) if x == 0 => { return from.clone() } _ => (), } match *self { Seconds(s) => from.clone() + Duration::seconds(s as i64), Minutes(m) => from.clone() + Duration::seconds(m as i64 * 60), Hours(h) => from.clone() + Duration::seconds(h as i64 * 3600), Days(d) => from.clone() + Duration::days(d as i64), Weeks(w) => from.clone() + Duration::days(w as i64 * 7), Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday => self.next(from), Weekday => { let d = from.date(); let dow = d.weekday(); let days = match dow { Weekday::Fri => 3, Weekday::Sat => 2, _ => 1, }; from.clone() + Duration::days(days) } } } } ``` -------------------------------- ### Schedule Simple Repeating Job Source: https://docs.rs/clokwerk/0.4.0/clokwerk/trait.Job.html Schedules a job to run three times at 45-minute intervals, starting from the initial scheduled time. If a job is still repeating, it will ignore otherwise scheduled runs. ```rust let mut scheduler = Scheduler::new(); scheduler.every(1.hour()) .repeating_every(45.minutes()) .times(3) .run(|| println!("Hello")); ``` -------------------------------- ### Calculate Next Run Time with Clokwerk Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/intervals.rs.html Calculates the next scheduled run time based on a starting datetime and a run configuration. Ensure DateTime and RunConfig are properly imported and initialized. ```rust let dt = DateTime::parse_from_rfc3339("2018-09-04T14:22:13-00:00").unwrap(); let rc = RunConfig::from_interval(Tuesday).with_time(NaiveTime::from_hms(0, 0, 0)); let next_dt = rc.next(&dt); let expected = DateTime::parse_from_rfc3339("2018-09-11T00:00:00-00:00").unwrap(); assert_eq!(next_dt, expected); ``` -------------------------------- ### Schedule Repeating Job Daily Source: https://docs.rs/clokwerk/0.4.0/clokwerk/trait.Job.html Schedules a job to run five times every day at 10-minute intervals, starting from a specific time. This affects all intervals associated with the job. ```rust let mut scheduler = Scheduler::new(); scheduler.every(Weekday) .at("7:40") .and_every(Saturday) .at("9:15") .and_every(Sunday) .at("9:15") .repeating_every(10.minutes()) .times(5) .run(|| hit_snooze()); ``` -------------------------------- ### Scheduler Initialization Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.Scheduler.html Methods for creating a new scheduler instance with optional timezone and time provider configurations. ```APIDOC ## Scheduler::new() ### Description Create a new scheduler. Dates and times will be interpreted using the local timezone. ## Scheduler::with_tz(tz: Tz) ### Description Create a new scheduler. Dates and times will be interpreted using the specified timezone. ## Scheduler::with_tz_and_provider(tz: Tz, tp: Tp) ### Description Create a new scheduler with a specified timezone and an alternate time provider, useful for testing. ``` -------------------------------- ### Adding Jobs to Scheduler Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/scheduler.rs.html Shows how to add jobs to a scheduler instance using the every method with various interval configurations. ```rust # use clokwerk::*; # use clokwerk::Interval::*; let mut scheduler = Scheduler::new(); scheduler.every(10.minutes()).plus(30.seconds()).run(|| println!("Periodic task")); scheduler.every(1.day()).at("3:20 pm").run(|| println!("Daily task")); scheduler.every(Wednesday).at("14:20:17").run(|| println!("Weekly task")); scheduler.every(Weekday).run(|| println!("Every weekday at midnight")); ``` -------------------------------- ### Basic AsyncScheduler Usage Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/async_scheduler.rs.html Demonstrates creating an AsyncScheduler and scheduling various types of asynchronous jobs using different interval and time specifications. Includes scheduling async blocks, functions, and boxed futures. ```rust # use clokwerk::{AsyncScheduler, TimeUnits, Job}; # use clokwerk::Interval::*; # use std::time::Duration; # use std::future::Future; # use std::pin::Pin; # async fn some_async_fn() {} # fn returns_boxed_future() -> Box + Send> { Box::new(some_async_fn()) } # fn returns_pinned_boxed_future() -> Pin + Send>> { Box::pin(some_async_fn()) } # # // Create a new scheduler # let mut scheduler = AsyncScheduler::new(); # // Add some tasks to it # scheduler # .every(10.minutes()) # .plus(30.seconds()) # .run(|| async { println!("Simplest is just using an async block"); }); # scheduler # .every(1.day()) # .at("3:20 pm") # .run(|| some_async_fn()); # scheduler # .every(Wednesday) # .at("14:20:17") # .run(some_async_fn); # scheduler # .every(Tuesday) # .at("14:20:17") # .and_every(Thursday) # .at("15:00") # .run(|| std::pin::Pin::from(returns_boxed_future())); # scheduler # .every(Weekday) # .run(|| returns_pinned_boxed_future()); # scheduler # .every(1.day()) # .at("3:20 pm") # .run(returns_pinned_boxed_future).once(); # tokio_test::block_on(async move { # // Manually run the scheduler forever # loop { # scheduler.run_pending().await; # tokio::time::sleep(Duration::from_millis(10)).await; # # break; # } # # // Or spawn a task to run it forever # tokio::spawn(async move { # loop { # scheduler.run_pending().await; # tokio::time::sleep(Duration::from_millis(100)).await; # } # }); # }); ``` -------------------------------- ### Helper function to get day of week index Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/intervals.rs.html Converts an `Interval` representing a specific day of the week into a numerical index (0-6). Returns 7 for non-day intervals. ```rust fn day_of_week(i: Interval) -> usize { match i { Monday => 0, Tuesday => 1, Wednesday => 2, Thursday => 3, Friday => 4, Saturday => 5, Sunday => 6, _ => 7, } } ``` -------------------------------- ### AsyncScheduler Initialization Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/async_scheduler.rs.html Shows how to create a new AsyncScheduler instance. It defaults to the local timezone and can be configured with a specific timezone. ```rust pub fn new() -> Self { Self::default() } ``` ```rust pub fn with_tz(tz: Tz) -> AsyncScheduler { AsyncScheduler { jobs: vec![], tz, _tp: PhantomData, } } ``` -------------------------------- ### Manage Job Scheduling and Execution Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job_schedule.rs.html Methods for initializing a schedule, checking pending status, and executing the next scheduled run. ```rust pub fn start_schedule(&mut self) -> &mut Self { if let None = self.next_run { let now = Tp::now(&self.tz); self.next_run = self.next_run_time(&now); match &mut self.repeat_config { Some(RepeatConfig { repeats, repeats_left, .. }) => { *repeats_left = *repeats; } None => (), } } self } /// Test whether a job is scheduled to run again. This is usually only called by /// [Scheduler::run_pending()](::Scheduler::run_pending). pub fn is_pending(&self, now: &DateTime) -> bool { match &self.next_run { Some(dt) => *dt <= *now, None => false, } } /// Run a task and re-schedule it. This is usually only called by /// [Scheduler::run_pending()](::Scheduler::run_pending). pub fn schedule_next(&mut self, now: &DateTime) { // Don't do anything if we're run out of runs if self.run_count == RunCount::Never { return; } // We compute this up front since we can't borrow self immutably while doing this next bit let next_run_time = self.next_run_time(now); match &mut self.repeat_config { Some(RepeatConfig { repeats, repeats_left, repeat_interval, }) => { if *repeats_left > 0 { *repeats_left -= 1; // Normal scheduling is aligned with the day: if you ask for something every hour, it will // run at the start of the next hour, not one hour after being scheduled. // For repeats, though, we want them aligned the first run of the repeats. // This means we want to align with with next_run (which should be not far in the past), // or if it's somehow unavailable, the current time. // It's possible that we're really far behind. If so, find the next repeat interval that's // still in the future (relative to when we start this run.) let mut next = self.next_run.as_ref().unwrap_or(now).clone(); loop { next = repeat_interval.next_from(&next); if next > *now { break; } } self.next_run = Some(next); } else { self.next_run = next_run_time; *repeats_left = *repeats; } } None => self.next_run = next_run_time, } self.last_run = Some(now.clone()); self.run_count = match self.run_count { RunCount::Never => RunCount::Never, RunCount::Times(n) if n > 1 => RunCount::Times(n - 1), RunCount::Times(_) => RunCount::Never, RunCount::Forever => RunCount::Forever, }; } ``` -------------------------------- ### Create a New Scheduler Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.Scheduler.html Instantiates a new Scheduler. Use `new()` for the local timezone or `with_tz()` to specify a timezone. ```rust let mut scheduler = Scheduler::new(); ``` ```rust let mut scheduler = Scheduler::with_tz(chrono::Utc); ``` ```rust let mut scheduler = Scheduler::with_tz_and_provider( tz: Tz, ) -> Scheduler ``` -------------------------------- ### Timeout Long-Running Asynchronous Tasks Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/async_scheduler.rs.html Schedules a job with a timeout to prevent it from running indefinitely. This example uses `tokio::time::timeout` to ensure the `scrape_pages` task completes within a specified duration. ```rust # use clokwerk::*; # use clokwerk::Interval::*; # async fn scrape_pages() {} use std::time::Duration; let mut scheduler = AsyncScheduler::new(); scheduler.every(10.minutes()).run(|| async { if let Err(_) = tokio::time::timeout(Duration::from_secs(10 * 60), scrape_pages()).await { eprintln!("Timed out scraping pages") } }); ``` -------------------------------- ### Configure and Calculate Next Run Time Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/intervals.rs.html Demonstrates using `RunConfig` to set intervals and specific times for task scheduling. Calculates the next scheduled run time based on a given datetime. ```rust let rc = RunConfig::from_interval(1.day()).with_time(NaiveTime::from_hms(15, 0, 0)); let dt = DateTime::parse_from_rfc3339("2018-09-04T14:22:13-00:00").unwrap(); let next_dt = rc.next(&dt); let expected = DateTime::parse_from_rfc3339("2018-09-04T15:00:00-00:00").unwrap(); assert_eq!(next_dt, expected); ``` ```rust let rc = RunConfig::from_interval(Tuesday).with_time(NaiveTime::from_hms(15, 0, 0)); let dt = DateTime::parse_from_rfc3339("2018-09-04T14:22:13-00:00").unwrap(); let next_dt = rc.next(&dt); let expected = DateTime::parse_from_rfc3339("2018-09-04T15:00:00-00:00").unwrap(); assert_eq!(next_dt, expected); ``` ```rust let rc = RunConfig::from_interval(Tuesday).with_time(NaiveTime::from_hms(14, 0, 0)); let next_dt = rc.next(&dt); let expected = DateTime::parse_from_rfc3339("2018-09-11T14:00:00-00:00").unwrap(); assert_eq!(next_dt, expected); ``` ```rust let rc = RunConfig::from_interval(Tuesday) .with_subinterval(6.hours()) .with_subinterval(5.minutes()); let next_dt = rc.next(&dt); let expected = DateTime::parse_from_rfc3339("2018-09-11T06:05:00-00:00").unwrap(); assert_eq!(next_dt, expected); ``` -------------------------------- ### Schedule Various Asynchronous Jobs with AsyncScheduler Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/async_scheduler.rs.html Demonstrates scheduling different types of asynchronous jobs using `every()`. Supports fixed intervals, intervals with offsets, specific times, and recurring days/weekdays. Ensure necessary imports for `Interval` variants and future types. ```rust # use clokwerk::*; # use clokwerk::Interval::*; # use std::future::Future; # use std::pin::Pin; # async fn some_async_fn() {} # fn returns_boxed_future() -> Box + Send> { Box::new(some_async_fn()) } # fn returns_pinned_boxed_future() -> Pin + Send>> { Box::pin(some_async_fn()) } let mut scheduler = AsyncScheduler::new(); scheduler.every(10.minutes()).plus(30.seconds()).run(|| async { println!("Periodic task") }); scheduler.every(1.day()).at("3:20 pm").run(|| some_async_fn()); scheduler.every(Wednesday).at("14:20:17").run(|| Pin::from(returns_boxed_future())); scheduler.every(Weekday).run(|| returns_pinned_boxed_future()); ``` -------------------------------- ### Try Setting Specific Run Time Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job_schedule.rs.html Safely attempts to configure the job to run at a specific time of day, returning a `Result` to handle potential parsing errors. ```rust pub fn try_at(&mut self, time: &str) -> Result<&mut Self, chrono::ParseError> { Ok(self.at_time(parse_time(time)?)) } ``` -------------------------------- ### SyncJob::run Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/sync_job.rs.html Defines the task to be executed by the job and initializes its schedule. ```APIDOC ## SyncJob::run ### Description Specifies a task to run and schedules its next execution time. ### Parameters #### Request Body - **f** (FnMut() + Send) - Required - The closure or function to be executed when the job runs. ### Response - **&mut Self** - Returns a mutable reference to the SyncJob instance for chaining. ``` -------------------------------- ### Initialize Job Schedule Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job_schedule.rs.html Creates a new `JobSchedule` with a default interval and timezone. The schedule is initially set to run forever. ```rust pub(crate) fn new(ival: Interval, tz: Tz) -> Self { Self { frequency: vec![RunConfig::from_interval(ival)], next_run: None, last_run: None, run_count: RunCount::Forever, repeat_config: None, tz, _tp: PhantomData, } } ``` -------------------------------- ### Create an AsyncScheduler with Timezone and TimeProvider Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/async_scheduler.rs.html Initializes an AsyncScheduler with a specific timezone and a custom TimeProvider. This is useful for testing or environments requiring precise time control. ```rust pub fn with_tz_and_provider( tz: Tz, ) -> AsyncScheduler { AsyncScheduler { jobs: vec![], tz, _tp: PhantomData, } } ``` -------------------------------- ### Scheduling a Job at a Specific Time (NaiveTime) Source: https://docs.rs/clokwerk/0.4.0/clokwerk/trait.Job.html Schedule a job using a `chrono::NaiveTime` object for precise timing without string parsing. ```rust let mut scheduler = Scheduler::new(); scheduler.every(Weekday).at_time(NaiveTime::from_hms(23, 42, 16)).run(|| println!("Also works with NaiveTime")); ``` -------------------------------- ### Test once scheduling Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/scheduler.rs.html Demonstrates scheduling a task to run exactly once using the once method. ```rust #[test] fn test_once() { make_time_provider!(FakeTimeProvider: "2019-10-22T12:40:01Z", "2019-10-22T12:40:01Z", "2019-10-22T12:40:02Z", "2019-10-22T12:40:03Z" ); let mut scheduler = Scheduler::with_tz_and_provider::(chrono::Utc); let times_called = Arc::new(AtomicU32::new(0)); { let times_called = times_called.clone(); scheduler.every(1.seconds()).once().run(move || { times_called.fetch_add(1, Ordering::SeqCst); }); } assert_eq!(1, TIMES_TIME_REQUESTED.load(Ordering::SeqCst)); scheduler.run_pending(); assert_eq!(2, TIMES_TIME_REQUESTED.load(Ordering::SeqCst)); assert_eq!(0, times_called.load(Ordering::SeqCst)); scheduler.run_pending(); assert_eq!(3, TIMES_TIME_REQUESTED.load(Ordering::SeqCst)); } ``` -------------------------------- ### Test every_at scheduling Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/scheduler.rs.html Demonstrates scheduling a task to run at a specific time of day using a fake time provider. ```rust #[test] fn test_every_at() { make_time_provider!(FakeTimeProvider: "2019-10-22T12:40:00Z", "2019-10-22T12:40:10Z", "2019-10-25T12:50:20Z", "2019-10-25T15:23:30Z", "2019-10-26T15:50:30Z" ); let mut scheduler = Scheduler::with_tz_and_provider::(chrono::Utc); let times_called = Arc::new(AtomicU32::new(0)); { let times_called = times_called.clone(); scheduler.every(3.days()).at("15:23").run(move || { times_called.fetch_add(1, Ordering::SeqCst); }); } assert_eq!(1, TIMES_TIME_REQUESTED.load(Ordering::SeqCst)); scheduler.run_pending(); assert_eq!(0, times_called.load(Ordering::SeqCst)); assert_eq!(2, TIMES_TIME_REQUESTED.load(Ordering::SeqCst)); scheduler.run_pending(); assert_eq!(1, times_called.load(Ordering::SeqCst)); assert_eq!(3, TIMES_TIME_REQUESTED.load(Ordering::SeqCst)); scheduler.run_pending(); assert_eq!(1, times_called.load(Ordering::SeqCst)); assert_eq!(4, TIMES_TIME_REQUESTED.load(Ordering::SeqCst)); } ``` -------------------------------- ### Macro for Creating Fake Time Providers Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/scheduler.rs.html A macro to simplify the creation of mock `TimeProvider` structs for testing purposes. It allows defining a sequence of times that the provider will return. ```rust # use clokwerk::TimeProvider; # use std::sync::{atomic::AtomicU32, atomic::Ordering}; macro_rules! make_time_provider { ($name:ident : $($time:literal),+) => { #[derive(Debug)] struct $name {} static TIMES_TIME_REQUESTED: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| AtomicU32::new(0)); impl TimeProvider for $name { fn now(tz: &Tz) -> chrono::DateTime where Tz: chrono::TimeZone + Sync + Send, { let times = [$(chrono::DateTime::parse_from_rfc3339($time).unwrap()),+]; let idx = TIMES_TIME_REQUESTED.fetch_add(1, Ordering::SeqCst) as usize; times[idx].with_timezone(&tz) } } }; } ``` -------------------------------- ### Schedule Initial Repeating Job Source: https://docs.rs/clokwerk/0.4.0/clokwerk/trait.Job.html Schedules a job to run five times every morning at 7:40, and then repeat every 10 minutes. This affects all intervals associated with the job. ```rust let mut scheduler = Scheduler::new(); scheduler.every(Weekday) .at("7:40") .repeating_every(10.minutes()) .times(5) .run(|| hit_snooze()); ``` -------------------------------- ### Create a New AsyncScheduler Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.AsyncScheduler.html Initializes a new AsyncScheduler. By default, it uses the local timezone. ```rust pub fn new() -> Self ``` -------------------------------- ### Scheduler API Source: https://docs.rs/clokwerk/0.4.0/clokwerk Overview of the synchronous and asynchronous scheduler structures provided by the Clokwerk crate. ```APIDOC ## Structs ### Scheduler - **Description**: Synchronous job scheduler. ### AsyncScheduler - **Description**: Asynchronous job scheduler, for use with Futures. ### SyncJob - **Description**: A job to run on the synchronous scheduler. Created via `Scheduler::every()`. ### AsyncJob - **Description**: An asynchronous job to run on the scheduler. Created via `AsyncScheduler::every()`. ### ScheduleHandle - **Description**: Guard object for the scheduler background thread. The thread is terminated if this object is dropped, or `ScheduleHandle::stop()` is called. ``` -------------------------------- ### Job Scheduling with Specific Times Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html This section details how to schedule jobs to run at specific times of the day using string representations or `chrono::NaiveTime` objects. ```APIDOC ## POST /api/jobs/schedule/at ### Description Schedules a job to run at a specific time of day. Supports various string formats for time and can also accept `chrono::NaiveTime`. ### Method POST ### Endpoint `/api/jobs/schedule/at` ### Parameters #### Query Parameters - **time** (string) - Required - The time of day to run the job (e.g., "14:32", "6:32:21 PM"). - **time** (chrono::NaiveTime) - Required - The specific time object to run the job. ### Request Body This endpoint does not directly accept a request body for scheduling parameters. Scheduling is configured via method calls. ### Request Example ```rust use clokwerk::*; use clokwerk::Interval::*; use chrono::NaiveTime; let mut scheduler = Scheduler::new(); // Using string scheduler.every(1.day()).at("14:32").run(|| println!("Tea time!")); scheduler.every(Wednesday).at("6:32:21 PM").run(|| println!("Writing examples is hard")); // Using NaiveTime scheduler.every(Weekday).at_time(NaiveTime::from_hms(23, 42, 16)).run(|| println!("Also works with NaiveTime")); ``` ### Response #### Success Response (200) Indicates successful scheduling. The response typically involves the scheduler object itself, allowing for chained operations. #### Response Example (No explicit response body, operation is reflected in the scheduler state) ``` -------------------------------- ### AsyncScheduler Blanket Implementations Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.AsyncScheduler.html Details various blanket implementations for AsyncScheduler, including Any, Borrow, BorrowMut, From, Into, TryFrom, and TryInto. ```APIDOC ## Blanket Implementations for AsyncScheduler ### Description This section covers standard blanket implementations that apply to `AsyncScheduler` due to its generic nature and common trait bounds. ### Implementations: 1. **Any** * **Description**: Allows the scheduler to be treated as a trait object. * **Method**: `type_id()` * **Example**: `let scheduler: &dyn Any = &my_scheduler;` 2. **Borrow** * **Description**: Provides immutable access to the scheduler. * **Method**: `borrow()` * **Example**: `let borrowed_scheduler: &AsyncScheduler = Borrow::borrow(&my_scheduler);` 3. **BorrowMut** * **Description**: Provides mutable access to the scheduler. * **Method**: `borrow_mut()` * **Example**: `let borrowed_mut_scheduler: &mut AsyncScheduler = BorrowMut::borrow_mut(&mut my_scheduler);` 4. **From** * **Description**: Allows creating an `AsyncScheduler` from itself (identity conversion). * **Method**: `from()` * **Example**: `let scheduler_from_self = AsyncScheduler::from(my_scheduler);` 5. **Into** * **Description**: Allows converting an `AsyncScheduler` into another type that can be created from it. * **Method**: `into()` * **Example**: `let scheduler_into_other: OtherType = my_scheduler.into();` 6. **TryFrom** * **Description**: Provides fallible conversion from another type into `AsyncScheduler`. * **Method**: `try_from()` * **Error Type**: `Infallible` (conversion is infallible) * **Example**: `let scheduler_try: AsyncScheduler = AsyncScheduler::try_from(some_value).unwrap();` 7. **TryInto** * **Description**: Provides fallible conversion from `AsyncScheduler` into another type. * **Method**: `try_into()` * **Error Type**: Depends on the target type's `TryFrom` implementation. * **Example**: `let other_type: OtherType = my_scheduler.try_into().unwrap();` ``` -------------------------------- ### Repeating Job Scheduling Source: https://docs.rs/clokwerk/0.4.0/clokwerk/trait.Job.html This section details how to schedule jobs to repeat at specified intervals after their initial run. It covers the `repeating_every` method and its interaction with other scheduling parameters like `at`, `and_every`, and `times`. ```APIDOC ## POST /jobs/schedule/repeat ### Description Schedules a job to run repeatedly at a specified interval after its initial execution. ### Method POST ### Endpoint /jobs/schedule/repeat ### Parameters #### Query Parameters - **interval** (Interval) - Required - The interval at which the job should repeat. - **times** (integer) - Optional - The number of times the job should repeat. ### Request Body ```json { "initial_schedule": { "day": "Weekday", "time": "7:40" }, "repeat_interval": "10.minutes", "repeat_times": 5 } ``` ### Response #### Success Response (200) - **job_id** (string) - The unique identifier for the scheduled job. #### Response Example ```json { "job_id": "job_12345" } ``` ``` -------------------------------- ### RunConfig::next (impl NextTime) Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/intervals.rs.html Calculates the next scheduled run time based on the RunConfig. ```APIDOC ## RunConfig::next (impl NextTime) ### Description Calculates the next occurrence of the schedule defined by the `RunConfig` after the given `from` datetime. It first applies the adjustment to the previous occurrence of the base interval and then checks if it's after the `from` datetime. If not, it applies the adjustment to the next occurrence of the base interval. ``` -------------------------------- ### Schedule Job at Specific Time (Result) Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.SyncJob.html Similar to `Job::at`, but returns a Result to handle potential parsing errors gracefully. ```rust fn try_at(&mut self, time: &str) -> Result<&mut Self, ParseError> ``` -------------------------------- ### Scheduler Methods Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.Scheduler.html Core methods available for the Scheduler struct. ```APIDOC ## fn fmt(&self, f: &mut Formatter<'_>) -> Result ### Description Formats the value using the given formatter. ## fn default() -> Self ### Description Returns the default value for the Scheduler type. ``` -------------------------------- ### Job Scheduling with Time Offsets Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html Details on how to apply time offsets to a job's schedule, allowing for more granular timing relative to the base interval. ```APIDOC ## POST /api/jobs/schedule/plus ### Description Applies a time offset to a scheduled job. This method is mutually exclusive with `at()` and `try_at()`. ### Method POST ### Endpoint `/api/jobs/schedule/plus` ### Parameters #### Query Parameters - **offset** (Duration) - Required - The duration to add as an offset to the job's schedule (e.g., 6.hours(), 13.minutes()). ### Request Body This endpoint does not directly accept a request body for scheduling parameters. Scheduling is configured via method calls. ### Request Example ```rust use clokwerk::*; use clokwerk::Interval::*; let mut scheduler = Scheduler::new(); scheduler.every(1.day()) .plus(6.hours()) .plus(13.minutes()) .run(|| println!("Time to wake up!")); // Example demonstrating offset exceeding base frequency scheduler.every(1.hour()) .plus(90.minutes()) .run(|| println!("Runs at 01:30, 02:30, etc.")); ``` ### Response #### Success Response (200) Indicates successful scheduling with offset. The response typically involves the scheduler object itself, allowing for chained operations. #### Response Example (No explicit response body, operation is reflected in the scheduler state) ``` -------------------------------- ### Schedule Job at Specific Time (NaiveTime) Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html Schedules a job to run at a specific time of day using a `chrono::NaiveTime` object. This method always succeeds as no string parsing is involved. ```rust scheduler.every(Weekday).at_time(NaiveTime::from_hms(23, 42, 16)).run(|| println!("Also works with NaiveTime")); ``` -------------------------------- ### Schedule Job at Specific Time (String) Source: https://docs.rs/clokwerk/0.4.0/src/clokwerk/job.rs.html Schedules a job to run at a specific time of day using a string format. Panics if the time string is invalid. Mutually exclusive with `plus()`. ```rust scheduler.every(1.day()).at("14:32").run(|| println!("Tea time!")); scheduler.every(Wednesday).at("6:32:21 PM").run(|| println!("Writing examples is hard")); ``` -------------------------------- ### NextTime Trait Methods Source: https://docs.rs/clokwerk/0.4.0/clokwerk/trait.NextTime.html Documentation for the required methods in the NextTime trait used for interval calculations. ```APIDOC ## Trait: NextTime ### Description A trait defining methods to calculate the next and previous occurrences of a time interval relative to a provided DateTime. ### Methods - **next(&self, from: &DateTime) -> DateTime** - Calculates the next occurrence after the provided DateTime. - **prev(&self, from: &DateTime) -> DateTime** - Calculates the previous occurrence before the provided DateTime. ### Implementation - **Implementors**: Interval ``` -------------------------------- ### Schedule Job at NaiveTime Source: https://docs.rs/clokwerk/0.4.0/clokwerk/struct.SyncJob.html Schedules a job using a chrono::NaiveTime object, avoiding string parsing and potential errors. ```rust fn at_time(&mut self, time: NaiveTime) -> &mut Self ```