Skip to content

Commit 639961d

Browse files
committed
Allow the resampler to use an external timestamp
This is necessary to achieve full timestamp consistency across the whole resampling machinery, otherwise there could be some inconsistencies when calculating which are the current relevant samples to use when resampling in the ComponentMetricResampler. The ComponentMetricGroupResampler now passes the timestamp to all the ComponentMetricResampler it controls. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent 9960656 commit 639961d

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

src/frequenz/sdk/timeseries/resampler.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,22 @@ def remove_outdated_samples(self, threshold: datetime) -> None:
7777

7878
self._buffer.popleft()
7979

80-
def resample(self) -> Optional[float]:
80+
def resample(self, timestamp: Optional[datetime] = None) -> Optional[float]:
8181
"""Resample samples from the buffer and produce a single sample.
8282
83+
Args:
84+
timestamp: the timestamp to use to as the current resampling
85+
timestamp when calculating which stored past samples are
86+
relevant to pass to the resampling function. If `None`, the
87+
current datetime (in UTC) will be used.
88+
8389
Returns:
8490
Samples resampled into a single sample or `None` if the
8591
`resampling_function` cannot produce a valid Sample.
8692
"""
87-
# It might be better to provide `now` from the outside so that all
88-
# individual resamplers use the same `now`
89-
now = datetime.now(timezone.utc)
90-
threshold = now - timedelta(
93+
if timestamp is None:
94+
timestamp = datetime.now(timezone.utc)
95+
threshold = timestamp - timedelta(
9196
seconds=self._max_data_age_in_periods * self._resampling_period_s
9297
)
9398
self.remove_outdated_samples(threshold=threshold)
@@ -182,4 +187,4 @@ def resample(self) -> Generator[Tuple[str, Sample], None, None]:
182187
"""
183188
now = datetime.now(timezone.utc)
184189
for time_series_id, resampler in self._resamplers.items():
185-
yield time_series_id, Sample(timestamp=now, value=resampler.resample())
190+
yield time_series_id, Sample(timestamp=now, value=resampler.resample(now))

tests/timeseries/test_resampling.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ def test_component_metric_resampler_remove_outdated_samples() -> None:
5656
resampler.add_sample(sample1)
5757
resampler.add_sample(sample2)
5858

59+
resampler.remove_outdated_samples(threshold=timestamp)
60+
assert list(resampler._buffer) == [
61+
sample1,
62+
sample2,
63+
] # pylint: disable=protected-access
64+
5965
resampler.remove_outdated_samples(threshold=timestamp + timedelta(seconds=0.5))
6066
assert list(resampler._buffer) == [sample2] # pylint: disable=protected-access
6167

@@ -72,13 +78,15 @@ def test_component_metric_resampler_resample() -> None:
7278
resampling_function=resampling_function_sum,
7379
)
7480

75-
timestamp = datetime.now(timezone.utc) - timedelta(seconds=0.5)
81+
now = datetime.now(timezone.utc)
82+
timestamp1 = now - timedelta(seconds=0.5)
83+
timestamp2 = now - timedelta(seconds=0.2)
7684

7785
value1 = 5.0
7886
value2 = 15.0
7987

80-
sample1 = Sample(timestamp, value=value1)
81-
sample2 = Sample(timestamp, value=value2)
88+
sample1 = Sample(timestamp1, value=value1)
89+
sample2 = Sample(timestamp2, value=value2)
8290

8391
resampler.add_sample(sample1)
8492
resampler.add_sample(sample2)
@@ -87,6 +95,10 @@ def test_component_metric_resampler_resample() -> None:
8795
assert value is not None
8896
assert value == sum([value1, value2])
8997

98+
value = resampler.resample(now + timedelta(seconds=0.6))
99+
assert value is not None
100+
assert value == value2
101+
90102

91103
@time_machine.travel(0, tick=False)
92104
def test_component_metric_resampler_resample_with_outdated_samples() -> None:

0 commit comments

Comments
 (0)