millipede_core/autoscale/
snapshotter.rs1use super::LoadSignal;
2use crate::errors::CrawlError;
3use std::{fmt, sync::Arc, time::Duration};
4
5#[derive(Clone)]
7#[non_exhaustive]
8#[must_use = "snapshotter options do nothing unless passed to Snapshotter::new"]
9pub struct SnapshotterOptions {
10 pub signals: Vec<Arc<dyn LoadSignal>>,
12 pub window: Duration,
14}
15
16impl Default for SnapshotterOptions {
17 fn default() -> Self {
18 Self {
19 signals: Vec::new(),
20 window: Duration::from_secs(30),
21 }
22 }
23}
24
25impl fmt::Debug for SnapshotterOptions {
26 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
27 formatter
28 .debug_struct("SnapshotterOptions")
29 .field("signal_count", &self.signals.len())
30 .field("window", &self.window)
31 .finish()
32 }
33}
34
35pub struct Snapshotter {
37 options: SnapshotterOptions,
38}
39
40impl Snapshotter {
41 pub fn new(options: SnapshotterOptions) -> Self {
43 Self { options }
44 }
45
46 pub fn signals(&self) -> &[Arc<dyn LoadSignal>] {
48 &self.options.signals
49 }
50
51 pub fn window(&self) -> Duration {
53 self.options.window
54 }
55
56 pub async fn start(&self) -> Result<(), CrawlError> {
58 for signal in &self.options.signals {
59 signal.start().await?;
60 }
61 Ok(())
62 }
63
64 pub async fn stop(&self) -> Result<(), CrawlError> {
66 let mut first_error = None;
67 for signal in &self.options.signals {
68 if let Err(error) = signal.stop().await {
69 if first_error.is_none() {
70 first_error = Some(error);
71 }
72 }
73 }
74 match first_error {
75 Some(error) => Err(error),
76 None => Ok(()),
77 }
78 }
79}