Skip to main content

max / makenotwork

3.3 KB · 96 lines History Blame Raw
1 //! Background check tasks spawned by `pom serve`, one spawner per check kind.
2
3 mod backup;
4 mod ca_bundle;
5 mod cors;
6 mod dns;
7 mod health;
8 mod meta_alert;
9 mod prune;
10 mod routes;
11 mod scan_pipeline;
12 mod synckit_fleet;
13 mod systemd;
14 mod test_suite;
15 mod tls;
16 mod whois;
17
18 use tokio_util::sync::CancellationToken;
19
20 use pom::config::{Config, TargetConfig};
21
22 /// The shared cadence of every background check: a fixed interval that skips its
23 /// immediate first tick, delays rather than bursts after a missed one, and yields
24 /// to cancellation without waiting out the remaining interval.
25 ///
26 /// This hands the caller a ticker instead of taking the check body as a callback.
27 /// A callback would have to borrow `pool`/`name`/the target config out of its own
28 /// captures across an await, which needs `AsyncFnMut::CallRefFuture` to name and
29 /// bound as `Send` (unstable). Driving the loop from the caller sidesteps that
30 /// entirely: every borrow stays local to the caller's own async block.
31 pub(crate) struct CheckInterval {
32 interval: tokio::time::Interval,
33 cancel: CancellationToken,
34 startup_tick_pending: bool,
35 }
36
37 impl CheckInterval {
38 pub(crate) fn new(interval_secs: u64, cancel: CancellationToken) -> Self {
39 let mut interval = tokio::time::interval(std::time::Duration::from_secs(interval_secs));
40 interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
41 Self {
42 interval,
43 cancel,
44 startup_tick_pending: true,
45 }
46 }
47
48 /// Wait for the next tick. Returns `false` once cancelled, so the call site
49 /// reads `while ticks.next().await { ... }`.
50 ///
51 /// The first call consumes the immediate startup tick, so a check fires one
52 /// full interval after boot rather than the instant the process starts.
53 pub(crate) async fn next(&mut self) -> bool {
54 if self.startup_tick_pending {
55 self.startup_tick_pending = false;
56 self.interval.tick().await;
57 }
58 tokio::select! {
59 () = self.cancel.cancelled() => false,
60 _ = self.interval.tick() => true,
61 }
62 }
63 }
64
65 /// Every configured target paired with its config, in `target_names` order.
66 ///
67 /// The spawners all opened with the same `for name in config.target_names()` /
68 /// `get_target(&name).unwrap().clone()` pair; the `unwrap` is only sound because
69 /// the name came from the map itself, which this keeps in one place.
70 pub(crate) fn configured_targets(
71 config: &Config,
72 ) -> impl Iterator<Item = (String, TargetConfig)> + use<'_> {
73 config.target_names().into_iter().map(|name| {
74 let target = config
75 .get_target(&name)
76 .expect("name came from target_names")
77 .clone();
78 (name, target)
79 })
80 }
81
82 pub(crate) use backup::spawn_backup_tasks;
83 pub(crate) use ca_bundle::spawn_ca_bundle_tasks;
84 pub(crate) use cors::spawn_cors_tasks;
85 pub(crate) use dns::spawn_dns_tasks;
86 pub(crate) use health::spawn_health_tasks;
87 pub(crate) use meta_alert::spawn_meta_alert_task;
88 pub(crate) use prune::spawn_prune_task;
89 pub(crate) use routes::spawn_route_tasks;
90 pub(crate) use scan_pipeline::spawn_scan_pipeline_tasks;
91 pub(crate) use synckit_fleet::spawn_synckit_fleet_tasks;
92 pub(crate) use systemd::spawn_systemd_tasks;
93 pub(crate) use test_suite::spawn_test_tasks;
94 pub(crate) use tls::spawn_tls_tasks;
95 pub(crate) use whois::spawn_whois_tasks;
96