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
//! [Periodically][crate] provides a robust and ergonomic library for writing periodic or scheduled jobs in Rust.
//!
//! ### The Scheduler
//!
//! The [Scheduler] is the core of periodically. It allows for tasks to be registered and scheduled.
//! It supports running synchronous [`Tasks`][Task] and asynchronous [`AsyncTasks`][AsyncTask] in the
//! same scheduling runtime.
//!
//! The core design of the scheduler is based on the idea of decoupling an executable task from it's schedule.
//!
//! For example, consider how this naive example of a periodic job requires so much boilerplate:
//!
//! ```
//! # use std::time::Duration;
//! # use std::sync::{Arc, atomic::AtomicBool};
//! # let should_terminate = true;
//! std::thread::spawn(move || {
//! loop {
//! // ..
//! // do the actual work
//! // ..
//! if should_terminate {
//! break;
//! }
//! std::thread::sleep(Duration::from_millis(100));
//! }
//! });
//! ```
//!
//! This example also fails to account for edge cases like panic resilience.
//!
//! Whereas with `periodically`, the task can easily without worrying about the schedule,
//! and then the schedule can be injected later. This also enables the re-use of schedules
//! if there is common specialized logic for your application.
//!
//! ```
//! # use periodically::Task;
//! # use periodically::Scheduler;
//! # use periodically::IntervalSchedule;
//! # use std::time::Duration;
//! # struct MyTask;
//! # let runtime = tokio::runtime::Builder::new_current_thread().build().unwrap();
//! impl Task for MyTask {
//! fn run(&self) {
//! // ..
//! // do the actual work
//! // ..
//! }
//! }
//! let mut scheduler = Scheduler::tokio_scheduler(runtime);
//! scheduler.add_sync_task(MyTask {}, IntervalSchedule::every(Duration::from_secs(100)));
//! ```
//!
//! [`Scheduler`] executes tasks in a serial fashion. aka; for every time a task is registered,
//! there is only ever at most one execution of that task.
//!
//! ### Tasks
//!
//! There are 2 types of task. The synchronous [`Task`], and it's async counterpart [`AsyncTask`].
//! Their interfaces are very similar, with the major difference being that [`AsyncTask`] returns a future that is [`Send`].
//!
//! Both types of task can be scheduled on the same [`Scheduler`], via [`add_sync_task`][Scheduler::add_sync_task]
//! and [`add_async_task`][Scheduler::add_async_task] respectively.
//!
//! ### Schedules
//!
//! The primary function of a [`Schedule`] is to consume context from a task execution, and decide when the next time that task will be executed.
//!
//! There are 3 control knobs of a [`Schedule`]:
//! 1. [`initial`][Schedule::initial] - this is called the very first time a task is being scheduled for execution.
//! 2. [`next`][Schedule::next] - this is called with the output of the last task execution.
//! 3. [`next_on_task_panic`][Schedule::next_on_task_panic] - this is called when the last task execution panicked.
//!
//! By using these knobs, and the internal state of the `impl Schedule`, there is a lot of flexibility in how dynamic schedulers can be built.
//! Additionally, since [`next`][Schedule::next] takes the output of the last task execution, an `impl Schedule` provides a way to egress
//! execution data via mechanims like mpsc channels if desired.
//!
//! ### Features
//!
//! By default, the only features enabled are `tokio` and `log`
//!
//! * `full`: Enables all features
//! * `tokio`: Enables the tokio-based scheduler. As of 0.2.0, this is the only scheduler, and essentially required.
//! * `log`: Enables an intergration with the [`log`] crate in the [`Scheduler`]. Helps provide debug information when dealing with problematic tasks.
//! * `backoff`: Adds a built-in [`Schedule`] named [`BackoffSchedule`] which uses the external [`backoff`] crate.
//! * `cron`: Adds a built-in [`Schedule`] named [`CronSchedule`] which uses the external [`cron`] crate.
/// Conditionally compiles a list of items under `feature_name`
/// and annotates the docs of pub items with "Available on crate feature `feature_name` only.".
///
/// eg;
///
/// ```compile_fail
/// cfg_feature! {
/// "my-feature",
/// pub mod my_feature;
/// }
/// ```
///
/// Transforms into
///
/// ```compile_fail
/// # asdf
/// #[cfg(feature = "my-feature")]
/// #[cfg_attr(docsrs, doc(cfg(feature = "my-feature")))]
/// pub mod my_feature;
/// ```
use Future;
pub use *;
pub use Scheduler;
pub use TaskIdentifier;
/// Defines a task that can run in an synchronous runtime.
/// Defines a task that can run in an asynchronous runtime.