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
//! Async scheduling for a single logical job at a time.
//!
//! The scheduler decides when to trigger work and persists the resulting job
//! state through a [`StateStore`]. Domain-specific retry, idempotency, and
//! cursor management remain in the caller.
//!
//! Key semantics:
//!
//! - [`Schedule::AtTimes`] waits until each planned timestamp and treats an
//! empty list as a no-op schedule.
//! - [`Schedule::Interval`] schedules the first run at `now + interval`.
//! - [`Schedule::Cron`] evaluates a standard 5-field cron expression in
//! [`SchedulerConfig::timezone`].
//! - [`Job::with_max_runs`] applies to every schedule kind; `0` exits without
//! running.
//! - [`SchedulerConfig::timezone`] is forwarded through [`RunContext`], drives
//! [`Schedule::Cron`] evaluation, and does not rewrite absolute
//! [`Schedule::AtTimes`] values.
//! - Restarts resume by `job_id` from the saved [`JobState::next_run_at`].
//! - Dependency injection here means passing an explicit `deps` value when the
//! job is constructed. The scheduler does not auto-resolve parameters.
//!
//! ```rust
//! use std::time::Duration;
//!
//! use scheduler::{InMemoryStateStore, Job, Schedule, Scheduler, SchedulerConfig, Task};
//!
//! let runtime = tokio::runtime::Runtime::new().unwrap();
//! runtime.block_on(async {
//! let scheduler = Scheduler::new(SchedulerConfig::default(), InMemoryStateStore::new());
//! let job = Job::without_deps(
//! "doc-simple",
//! Schedule::Interval(Duration::from_millis(1)),
//! Task::from_async(|_| async { Ok(()) }),
//! )
//! .with_max_runs(1);
//!
//! let report = scheduler.run(job).await.unwrap();
//! assert_eq!(report.history.len(), 1);
//! });
//! ```
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ValkeyStateStore;