Skip to content

Commit

Permalink
#69 - Fix an issue with the callback iteration timestamp drifting (#70)
Browse files Browse the repository at this point in the history
The callback iteration slowly drifts a few milliseconds per call
This is due to inaccuracies of time.sleep and some overhead on the `_run_callback` method

This fix the issue by using sched.enterabs instead of sched.enter.
This time to enter is always calculated based on the start timestamp of the callback

There will still be some milliseconds variation from execution to execution, but it will never drift.
  • Loading branch information
dlopes7 authored Jun 22, 2024
1 parent 03898ec commit d77e6ab
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 3 deletions.
2 changes: 1 addition & 1 deletion dynatrace_extension/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
#
# SPDX-License-Identifier: MIT

__version__ = "1.2.2"
__version__ = "1.2.3"
11 changes: 10 additions & 1 deletion dynatrace_extension/sdk/callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def __init__(
self.ok_count = 0 # counter per interval = 1 min by default
self.timeouts_count = 0 # counter per interval = 1 min by default
self.exception_count = 0 # counter per interval = 1 min by default
self.iterations = 0 # how many times we ran the callback iterator for this callback

def get_current_time_with_cluster_diff(self):
return datetime.now() + timedelta(milliseconds=self.cluster_time_diff)
Expand All @@ -56,7 +57,6 @@ def __call__(self):
self.running = True
self.executions_total += 1
self.executions_per_interval += 1
self.next_run = datetime.now() + self.interval
start_time = timer()
failed = False
try:
Expand Down Expand Up @@ -133,3 +133,12 @@ def clear_sfm_metrics(self):
self.duration_interval_total = 0
self.exception_count = 0
self.executions_per_interval = 0

def get_next_execution_timestamp(self) -> float:
"""
Get the timestamp for the next execution of the callback
This is done using execution total, the interval and the start timestamp
:return: datetime
"""
return (self.start_timestamp + timedelta(seconds=self.interval.total_seconds() * (self.iterations or 1))).timestamp()

4 changes: 3 additions & 1 deletion dynatrace_extension/sdk/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,9 @@ def _run_callback(self, callback: WrappedCallback):

def _callback_iteration(self, callback: WrappedCallback):
self._callbacks_executor.submit(self._run_callback, callback)
self._scheduler.enter(callback.interval.total_seconds(), 1, self._callback_iteration, (callback,))
callback.iterations += 1
next_timestamp = callback.get_next_execution_timestamp()
self._scheduler.enterabs(next_timestamp, 1, self._callback_iteration, (callback,))

def _start_extension_loop(self):
api_logger.debug(f"Starting main loop for monitoring configuration: '{self.monitoring_config_name}'")
Expand Down

0 comments on commit d77e6ab

Please sign in to comment.