Skip to content

Commit c08396c

Browse files
committed
Allow configuring resampler's max_age_in_intervals in LogicalMeter
Signed-off-by: Sahas Subramanian <sahas.subramanian@proton.me>
1 parent 65c5e4a commit c08396c

3 files changed

Lines changed: 75 additions & 1 deletion

File tree

src/logical_meter/config.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ pub struct LogicalMeterConfig {
1616
pub(crate) resampling_function: Option<ResamplingFunction<f32, Sample<f32>>>,
1717
/// Resampler overrides.
1818
pub(crate) resampling_overrides: HashMap<Metric, ResamplingFunction<f32, Sample<f32>>>,
19+
/// The maximum age of samples to be considered for resampling, in number of
20+
/// intervals.
21+
pub(crate) max_age_in_intervals: u32,
1922
}
2023

2124
impl LogicalMeterConfig {
@@ -25,6 +28,7 @@ impl LogicalMeterConfig {
2528
resampling_interval,
2629
resampling_function: None,
2730
resampling_overrides: HashMap::new(),
31+
max_age_in_intervals: 3,
2832
}
2933
}
3034

@@ -55,4 +59,17 @@ impl LogicalMeterConfig {
5559

5660
self
5761
}
62+
63+
/// Sets the maximum age of samples to be considered for resampling, in
64+
/// number of intervals.
65+
///
66+
/// Must be at least 1. If a smaller value is provided, it will be clamped
67+
/// to 1.
68+
///
69+
/// If not set, the default value is 3.
70+
pub fn with_max_age_in_intervals(mut self, max_age_in_intervals: u32) -> Self {
71+
// Ensure that the maximum age is at least 1 interval.
72+
self.max_age_in_intervals = max_age_in_intervals.max(1);
73+
self
74+
}
5875
}

src/logical_meter/logical_meter_actor.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,9 @@ impl LogicalMeterActor {
383383
// Finally, default to average if no default is
384384
// configured
385385
.unwrap_or(ResamplingFunction::Average),
386-
3,
386+
// The resampler expects max age to be i32, so we need to
387+
// cap it if the user provided a higher value.
388+
self.config.max_age_in_intervals.min(i32::MAX as u32) as i32,
387389
self.resampler_ts,
388390
false,
389391
),

src/logical_meter/logical_meter_handle.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,61 @@ mod tests {
473473
);
474474
}
475475

476+
#[tokio::test(start_paused = true)]
477+
async fn test_max_age_in_intervals() {
478+
let lm_config = Some(
479+
LogicalMeterConfig::new(TimeDelta::try_milliseconds(200).unwrap())
480+
.with_max_age_in_intervals(1)
481+
.with_default_resampling_function(ResamplingFunction::Count),
482+
);
483+
let mut lm = new_logical_meter_handle(lm_config).await;
484+
let formula = lm.consumer(crate::metric::AcPowerActive).unwrap();
485+
486+
let samples = fetch_samples(formula, 8).await;
487+
check_samples(
488+
samples,
489+
|q| q.as_watts(),
490+
TimeDelta::try_milliseconds(200).unwrap(),
491+
vec![
492+
Some(1.0),
493+
Some(1.0),
494+
Some(1.0),
495+
Some(1.0),
496+
Some(1.0),
497+
Some(1.0),
498+
Some(0.0),
499+
Some(0.0),
500+
],
501+
);
502+
503+
let lm_config = Some(
504+
LogicalMeterConfig::new(TimeDelta::try_milliseconds(200).unwrap())
505+
.with_max_age_in_intervals(3)
506+
.with_default_resampling_function(ResamplingFunction::Count),
507+
);
508+
let mut lm = new_logical_meter_handle(lm_config).await;
509+
let formula = lm.consumer(crate::metric::AcPowerActive).unwrap();
510+
511+
let samples = fetch_samples(formula, 10).await;
512+
check_samples(
513+
samples,
514+
|q| q.as_watts(),
515+
TimeDelta::try_milliseconds(200).unwrap(),
516+
vec![
517+
Some(1.0),
518+
Some(2.0),
519+
Some(3.0),
520+
Some(3.0),
521+
Some(3.0),
522+
Some(3.0),
523+
Some(2.0),
524+
Some(1.0),
525+
Some(0.0),
526+
Some(0.0),
527+
],
528+
)
529+
}
530+
476531
#[tokio::test(start_paused = true)]
477532
async fn test_consumer_current_formula() {
478533
let formula = new_logical_meter_handle(None)

0 commit comments

Comments
 (0)