1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
use crate::job_schedule::{Repeating, WithSchedule};
use crate::{timeprovider::TimeProvider, Interval};
use chrono::prelude::*;
/// This trait provides an abstraction over [`SyncJob`](crate::SyncJob) and [`AsyncJob`](crate::AsyncJob), covering all the methods relating to scheduling, rather than execution.
pub trait Job<Tz, Tp>: WithSchedule<Tz, Tp> + Sized
where
Tz: TimeZone + Sync + Send,
Tp: TimeProvider,
{
/// Specify the time of day when a task should run, e.g.
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # use chrono::NaiveTime;
/// let mut scheduler = Scheduler::new();
/// 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"));
/// ```
/// Times can be specified using strings, with or without seconds, and in either 24-hour or 12-hour time.
/// They can also be any other type that implements `TryInto<ClokwerkTime>`, which includes [`chrono::NaiveTime`].
/// This method will panic if TryInto fails, e.g. because the time string could not be parsed.
/// If the value comes from an untrusted source, e.g. user input, [`Job::try_at`] will return a result instead.
///
/// This method is mutually exclusive with [`Job::plus()`].
fn at(&mut self, time: &str) -> &mut Self {
self.schedule_mut()
.try_at(time)
.expect("Could not convert value into a time");
self
}
/// Identical to [`Job::at`] except that it returns a Result instead of panicking if the conversion failed.
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// let mut scheduler = Scheduler::new();
/// scheduler.every(1.day()).try_at("14:32")?.run(|| println!("Tea time!"));
/// # Ok::<(), chrono::ParseError>(())
/// ```
/// Times can be specified with or without seconds, and in either 24-hour or 12-hour time.
/// Mutually exclusive with [`Job::plus()`].
fn try_at(&mut self, time: &str) -> Result<&mut Self, chrono::ParseError> {
self.schedule_mut().try_at(time)?;
Ok(self)
}
/// Similar to [`Job::at`], but it takes a chrono::NaiveTime instead of a `&str`.
/// Because it doesn't need to parse a string, this method will always succeed.
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # use chrono::NaiveTime;
/// let mut scheduler = Scheduler::new();
/// scheduler.every(Weekday).at_time(NaiveTime::from_hms(23, 42, 16)).run(|| println!("Also works with NaiveTime"));
/// ```
fn at_time(&mut self, time: NaiveTime) -> &mut Self {
self.schedule_mut().at_time(time);
self
}
/// Specifies an offset to when a task should run, e.g.
/// ```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!"));
/// ```
/// Mutually exclusive with [`Job::at()`].
///
/// Note that this normally won't change the frequency with which a task runs, merely its timing.
/// For instance,
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # let mut scheduler = Scheduler::new();
/// scheduler.every(1.hour())
/// .plus(30.minutes())
/// .run(|| println!("Time to wake up!"));
/// ```
/// will run at 00:30, 01:30, 02:30, etc., rather than at 00:00, 01:30, 03:00, etc.
///
/// If that schedule is desired, then one would need to write
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # let mut scheduler = Scheduler::new();
/// scheduler.every(90.minutes())
/// .run(|| println!("Time to wake up!"));
/// ```
///
/// If the total offset exceeds the base frequency, the resulting behaviour can be unintuitive. For example,
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # let mut scheduler = Scheduler::new();
/// scheduler.every(1.hour())
/// .plus(90.minutes())
/// .run(|| println!("Time to wake up!"));
/// ```
/// will run at 01:30, 02:30, 03:30, etc., while
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # let mut scheduler = Scheduler::new();
/// scheduler.every(1.hour())
/// .plus(125.minutes())
/// .run(|| println!("Time to wake up!"));
/// ```
/// will run at 02:05, 04:05, 06:05, etc.
fn plus(&mut self, ival: Interval) -> &mut Self {
self.schedule_mut().plus(ival);
self
}
/// Add an additional scheduling to the task. All schedules will be considered when determining
/// when the task should next run.
fn and_every(&mut self, ival: Interval) -> &mut Self {
self.schedule_mut().and_every(ival);
self
}
/// Execute the job only once. Equivalent to `_.count(1)`.
fn once(&mut self) -> &mut Self {
self.schedule_mut().once();
self
}
/// Execute the job forever. This is the default behaviour.
fn forever(&mut self) -> &mut Self {
self.schedule_mut().forever();
self
}
/// Execute the job only `count` times.
fn count(&mut self, count: usize) -> &mut Self {
self.schedule_mut().count(count);
self
}
/// After running once, run again with the specified interval.
///
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # fn hit_snooze() {}
/// let mut scheduler = Scheduler::new();
/// scheduler.every(Weekday)
/// .at("7:40")
/// .repeating_every(10.minutes())
/// .times(5)
/// .run(|| hit_snooze());
/// ```
/// will hit snooze five times every morning, at 7:40, 7:50, 8:00, 8:10 and 8:20.
///
/// Unlike [`Job::at`] and [`Job::plus`],
/// this affects all intervals associated with the job, not just the most recent one.
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # fn hit_snooze() {}
/// 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());
/// ```
/// hits snooze five times every day, not just Sundays.
///
/// If a job is still repeating, it will ignore otherwise scheduled runs.
/// ```rust
/// # use clokwerk::*;
/// # use clokwerk::Interval::*;
/// # fn hit_snooze() {}
/// let mut scheduler = Scheduler::new();
/// scheduler.every(1.hour())
/// .repeating_every(45.minutes())
/// .times(3)
/// .run(|| println!("Hello"));
/// ```
/// If this is scheduled to run at 6 AM, it will print `Hello` at 6:00, 6:45, and 7:30, and then again at 8:00, 8:45, 9:30, etc.
fn repeating_every(&mut self, interval: Interval) -> Repeating<Self, Tz, Tp> {
Repeating::new(self, interval)
}
/// Test whether a job is scheduled to run again. This is usually only called by
/// [Scheduler::run_pending()](crate::Scheduler::run_pending).
fn is_pending(&self, now: &DateTime<Tz>) -> bool {
self.schedule().is_pending(now)
}
}