@cryptotaxi247 / netdata-1 / commits / 44eef8d10

python.d: use real time for calc sinceLast (#4720)

* use real time clock to calc since last update * python.d: remove unused attr from RuntimeCounters

Ilya Mashchenko committed Nov 26, 2018 at 12:43 UTC 44eef8d1039dfea033a1caeb3e7fcfcc5d34a828
3 files changed +54 -59
collectors/python.d.plugin/python_modules/bases/FrameworkServices/SimpleService.py
+52 -57
@@ -5,7 +5,7 @@
5 # SPDX-License-Identifier: GPL-3.0-or-later
6
7 from threading import Thread
8 -from time import sleep
8 +from time import sleep, time
9
10 from third_party.monotonic import monotonic
11
@@ -17,25 +17,42 @@ RUNTIME_CHART_UPDATE = 'BEGIN netdata.runtime_{job_name} {since_last}\n' \
17 'SET run_time = {elapsed}\n' \
18 'END\n'
19
20 +PENALTY_EVERY = 5
21 +
22
23 class RuntimeCounters:
24 def __init__(self, configuration):
25 """
26 :param configuration: <dict>
27 """
26 - self.FREQ = int(configuration.pop('update_every'))
27 - self.START_RUN = 0
28 - self.NEXT_RUN = 0
29 - self.PREV_UPDATE = 0
30 - self.SINCE_UPDATE = 0
31 - self.ELAPSED = 0
32 - self.RETRIES = 0
33 - self.RETRIES_MAX = configuration.pop('retries')
34 - self.PENALTY = 0
35 - self.RUNS = 1
36 -
37 - def is_sleep_time(self):
38 - return self.START_RUN < self.NEXT_RUN
28 + self.update_every = int(configuration.pop('update_every'))
29 + self.max_retries = int(configuration.pop('retries'))
30 +
31 + self.start_mono = 0
32 + self.start_real = 0
33 + self.retries = 0
34 + self.penalty = 0
35 + self.elapsed = 0
36 + self.prev_update = 0
37 + self.runs = 1
38 +
39 + def calc_next(self):
40 + self.start_mono = monotonic()
41 + return self.start_mono - (self.start_mono % self.update_every) + self.update_every + self.penalty
42 +
43 + def sleep_until_next(self):
44 + next_time = self.calc_next()
45 + while self.start_mono < next_time:
46 + sleep(next_time - self.start_mono)
47 + self.start_mono = monotonic()
48 + self.start_real = time()
49 +
50 + def handle_retries(self):
51 + self.retries += 1
52 + if self.retries % PENALTY_EVERY:
53 + return True
54 + self.penalty = self.retries * self.update_every / 2
55 + return self.retries < self.max_retries
56
57
58 class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, object):
@@ -83,11 +100,11 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
100
101 @property
102 def runs_counter(self):
86 - return self._runtime_counters.RUNS
103 + return self._runtime_counters.runs
104
105 @property
106 def update_every(self):
90 - return self._runtime_counters.FREQ
107 + return self._runtime_counters.update_every
108
109 @update_every.setter
110 def update_every(self, value):
@@ -95,7 +112,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
112 :param value: <int>
113 :return:
114 """
98 - self._runtime_counters.FREQ = value
115 + self._runtime_counters.update_every = value
116
117 def get_update_every(self):
118 return self.update_every
@@ -163,41 +180,40 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
180 :return: None
181 """
182 job = self._runtime_counters
166 - self.debug('started, update frequency: {freq}, '
167 - 'retries: {retries}'.format(freq=job.FREQ, retries=job.RETRIES_MAX - job.RETRIES))
183 + self.debug('started, update frequency: {freq}, retries: {retries}'.format(
184 + freq=job.update_every,
185 + retries=job.max_retries - job.retries),
186 + )
187
188 while True:
170 - job.START_RUN = monotonic()
171 -
172 - job.NEXT_RUN = job.START_RUN - (job.START_RUN % job.FREQ) + job.FREQ + job.PENALTY
173 -
174 - self.sleep_until_next_run()
189 + job.sleep_until_next()
190
176 - if job.PREV_UPDATE:
177 - job.SINCE_UPDATE = int((job.START_RUN - job.PREV_UPDATE) * 1e6)
191 + since = 0
192 + if job.prev_update:
193 + since = int((job.start_real - job.prev_update) * 1e6)
194
195 try:
180 - updated = self.update(interval=job.SINCE_UPDATE)
196 + updated = self.update(interval=since)
197 except Exception as error:
198 self.error('update() unhandled exception: {error}'.format(error=error))
199 updated = False
200
185 - job.RUNS += 1
201 + job.runs += 1
202
203 if not updated:
188 - if not self.manage_retries():
204 + if not job.handle_retries():
205 return
206 else:
191 - job.ELAPSED = int((monotonic() - job.START_RUN) * 1e3)
192 - job.PREV_UPDATE = job.START_RUN
193 - job.RETRIES, job.PENALTY = 0, 0
207 + job.elapsed = int((monotonic() - job.start_mono) * 1e3)
208 + job.prev_update = job.start_real
209 + job.retries, job.penalty = 0, 0
210 safe_print(RUNTIME_CHART_UPDATE.format(job_name=self.name,
195 - since_last=job.SINCE_UPDATE,
196 - elapsed=job.ELAPSED))
211 + since_last=since,
212 + elapsed=job.elapsed))
213 self.debug('update => [{status}] (elapsed time: {elapsed}, '
214 'retries left: {retries})'.format(status='OK' if updated else 'FAILED',
199 - elapsed=job.ELAPSED if updated else '-',
200 - retries=job.RETRIES_MAX - job.RETRIES))
215 + elapsed=job.elapsed if updated else '-',
216 + retries=job.max_retries - job.retries))
217
218 def update(self, interval):
219 """
@@ -233,27 +249,6 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
249
250 return updated
251
236 - def manage_retries(self):
237 - rc = self._runtime_counters
238 - rc.RETRIES += 1
239 - if rc.RETRIES % 5 == 0:
240 - rc.PENALTY = int(rc.RETRIES * self.update_every / 2)
241 - if rc.RETRIES >= rc.RETRIES_MAX:
242 - self.error('stopped after {0} data collection failures in a row'.format(rc.RETRIES_MAX))
243 - return False
244 - return True
245 -
246 - def sleep_until_next_run(self):
247 - job = self._runtime_counters
248 -
249 - # sleep() is interruptable
250 - while job.is_sleep_time():
251 - sleep_time = job.NEXT_RUN - job.START_RUN
252 - self.debug('sleeping for {sleep_time} to reach frequency of {freq} sec'.format(sleep_time=sleep_time,
253 - freq=job.FREQ + job.PENALTY))
254 - sleep(sleep_time)
255 - job.START_RUN = monotonic()
256 -
252 def get_data(self):
253 return self._get_data()
254
collectors/python.d.plugin/python_modules/bases/charts.py
+1 -1
@@ -45,7 +45,7 @@ def create_runtime_chart(func):
45 ok = func(*args, **kwargs)
46 if ok:
47 safe_print(RUNTIME_CHART_CREATE.format(job_name=self.name,
48 - update_every=self._runtime_counters.FREQ))
48 + update_every=self._runtime_counters.update_every))
49 return ok
50 return wrapper
51
collectors/python.d.plugin/python_modules/bases/loggers.py
+1 -1
@@ -34,7 +34,7 @@ def limiter(log_max_count=30, allowed_in_seconds=60):
34 def on_decorator(func):
35
36 def on_call(*args):
37 - current_time = args[0]._runtime_counters.START_RUN
37 + current_time = args[0]._runtime_counters.start_mono
38 lc = args[0]._logger_counters
39
40 if lc.logged and lc.logged % log_max_count == 0: