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
//! Retention (TTL) config for finished-run workbenches.
//!
//! A finished workbench is reaped once it is older than its routine's TTL (see the cleanup module).
//! Retention is kept short: a finished run is worth keeping only until the next run is due, and
//! never longer than [`MAX_TTL_SECS`]. So the effective TTL is `min(MAX_TTL_SECS, cron interval)`,
//! optionally lowered further by an explicit `ttl_secs`.
use Local;
use Routine;
/// Upper bound on how long a finished run's workbench is retained: one hour.
///
/// Also the fallback when a routine's schedule can't be parsed (e.g. `@reboot`) or its interval
/// can't be computed, and the retention for orphaned workbenches whose routine was since deleted.
pub const MAX_TTL_SECS: u64 = 60 * 60;
/// Cron-derived retention ceiling for a routine running on `schedule`:
/// `min(MAX_TTL_SECS, cron interval)`.
///
/// An explicit `ttl_secs` above this is silently clamped by [`Routine::effective_ttl_secs`], so
/// create/update validation rejects it instead (#468).
pub
/// How many consecutive future fires to sample when hunting for `schedule`'s shortest gap.
/// Comfortably covers multi-fire-per-day schedules (the only ones where the gap can dip below
/// [`MAX_TTL_SECS`]) across a multi-day look-ahead window; iterating a cron schedule is cheap, so
/// there's no cost pressure to trim it further.
const GAP_SAMPLE_FIRES: usize = 48;
/// The minimum gap (seconds) between consecutive entries in `fires`, sampling up to
/// [`GAP_SAMPLE_FIRES`] of them. `None` if `fires` yields fewer than two timestamps.
///
/// Shared by [`cron_interval_secs`] so the sampling stays stable for unevenly-spaced schedules.
/// The shortest gap between consecutive scheduled runs of `schedule`, or `None` if it can't be
/// parsed or fewer than two future fire times exist.
///
/// Takes the *minimum* gap across up to [`GAP_SAMPLE_FIRES`] consecutive fires after `now`,
/// rather than just the next two — for an unevenly-spaced schedule, "the next two fires from now"
/// alone depends on where `now` falls. E.g. `"0,30 9 * * *"` (fires at 09:00 and 09:30 daily) has
/// a true 30-minute minimum gap, but sampling only the next two fires gives 30 minutes when `now`
/// is just before 09:00 and ~23.5 hours when `now` is just after 09:00. Sampling multiple fires
/// keeps the result stable regardless of `now`, so sub-hour schedules (the only ones this
/// affects, since the result is only ever used via `MAX_TTL_SECS.min(..)`) really do have a
/// constant interval as callers assume.
pub