diff --git a/src/newrelic_telemetry_sdk/harvester.py b/src/newrelic_telemetry_sdk/harvester.py index 4fc29c0..e226e7a 100644 --- a/src/newrelic_telemetry_sdk/harvester.py +++ b/src/newrelic_telemetry_sdk/harvester.py @@ -64,7 +64,7 @@ def __init__(self, client, batch, harvest_interval=5): self.client = client self.batch = batch self.harvest_interval = harvest_interval - self._harvest_interval_start = 0 + self._harvest_interval_start = None self._shutdown = self.EVENT_CLS() def _send(self): @@ -83,11 +83,13 @@ def _send(self): def _wait_for_harvest(self): """Tracks and adjusts time required to maintain the harvest interval""" - current_time = time.time() - interval_start = self._harvest_interval_start or current_time + current_time = time.monotonic() + interval_start = self._harvest_interval_start + if interval_start is None: + interval_start = current_time timeout = max(self.harvest_interval - (current_time - interval_start), 0) shutdown = self._shutdown.wait(timeout) - self._harvest_interval_start = time.time() + self._harvest_interval_start = time.monotonic() return shutdown def run(self): diff --git a/tests/test_harvester.py b/tests/test_harvester.py index 0059c0f..8df1983 100644 --- a/tests/test_harvester.py +++ b/tests/test_harvester.py @@ -202,7 +202,7 @@ def _wait(t): timeout.append(t) return True - monkeypatch.setattr(time, "time", _time, raising=True) + monkeypatch.setattr(time, "monotonic", _time, raising=True) harvester._shutdown.wait = _wait # First call should result in full timeout @@ -217,3 +217,20 @@ def _wait(t): def test_defaults(harvester): assert harvester.daemon is True assert harvester.harvest_interval == 5 + + +@pytest.mark.parametrize("clock_change", [-3600, 3600]) +def test_harvest_interval_ignores_wall_clock_changes(harvester, monkeypatch, clock_change): + wall_time = [10000] + elapsed_time = [100] + timeouts = [] + monkeypatch.setattr(time, "time", lambda: wall_time[0]) + monkeypatch.setattr(time, "monotonic", lambda: elapsed_time[0]) + harvester._shutdown.wait = timeouts.append + + harvester._wait_for_harvest() + wall_time[0] += clock_change + elapsed_time[0] += 2 + harvester._wait_for_harvest() + + assert timeouts == [5, 3]