increase performance of executeCmd (actions), thereby introduced new shorter interval for fast operations (leaves unchanged default wait operation intervals (sleep time, threshold interval) - for the same inertance, to save same system (load by many jails resp. log files);

extends wait_for with callable timeout (test case fixed);
pull/1562/head
sebres 2016-09-29 20:47:10 +02:00
parent 5151c4fa6d
commit b011cf17b2
3 changed files with 43 additions and 17 deletions

View File

@ -54,6 +54,7 @@ class Utils():
DEFAULT_SLEEP_TIME = 2 DEFAULT_SLEEP_TIME = 2
DEFAULT_SLEEP_INTERVAL = 0.2 DEFAULT_SLEEP_INTERVAL = 0.2
DEFAULT_SHORT_INTERVAL = 0.001
class Cache(object): class Cache(object):
@ -134,21 +135,22 @@ class Utils():
""" """
stdout = stderr = None stdout = stderr = None
retcode = None retcode = None
if not callable(timeout):
stime = time.time()
timeout_expr = lambda: time.time() - stime <= timeout
else:
timeout_expr = timeout
popen = None popen = None
try: try:
popen = subprocess.Popen( popen = subprocess.Popen(
realCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell, realCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell,
preexec_fn=os.setsid # so that killpg does not kill our process preexec_fn=os.setsid # so that killpg does not kill our process
) )
# wait with timeout for process has terminated:
retcode = popen.poll() retcode = popen.poll()
while retcode is None and timeout_expr(): if retcode is None:
time.sleep(Utils.DEFAULT_SLEEP_INTERVAL) def _popen_wait_end():
retcode = popen.poll() retcode = popen.poll()
return (True, retcode) if retcode is not None else None
retcode = Utils.wait_for(_popen_wait_end, timeout, Utils.DEFAULT_SHORT_INTERVAL)
if retcode:
retcode = retcode[1]
# if timeout:
if retcode is None: if retcode is None:
logSys.error("%s -- timed out after %s seconds." % logSys.error("%s -- timed out after %s seconds." %
(realCmd, timeout)) (realCmd, timeout))
@ -202,18 +204,18 @@ class Utils():
success = False success = False
if retcode == 0: if retcode == 0:
logSys.debug("%s -- returned successfully", realCmd) logSys.debug("%-.40s -- returned successfully", realCmd)
success = True success = True
elif retcode is None: elif retcode is None:
logSys.error("%s -- unable to kill PID %i" % (realCmd, popen.pid)) logSys.error("%-.40s -- unable to kill PID %i", realCmd, popen.pid)
elif retcode < 0 or retcode > 128: elif retcode < 0 or retcode > 128:
# dash would return negative while bash 128 + n # dash would return negative while bash 128 + n
sigcode = -retcode if retcode < 0 else retcode - 128 sigcode = -retcode if retcode < 0 else retcode - 128
logSys.error("%s -- killed with %s (return code: %s)" % logSys.error("%-.40s -- killed with %s (return code: %s)",
(realCmd, signame.get(sigcode, "signal %i" % sigcode), retcode)) realCmd, signame.get(sigcode, "signal %i" % sigcode), retcode)
else: else:
msg = _RETCODE_HINTS.get(retcode, None) msg = _RETCODE_HINTS.get(retcode, None)
logSys.error("%s -- returned %i" % (realCmd, retcode)) logSys.error("%-.40s -- returned %i", realCmd, retcode)
if msg: if msg:
logSys.info("HINT on %i: %s", retcode, msg % locals()) logSys.info("HINT on %i: %s", retcode, msg % locals())
return success if not output else (success, stdout, stderr, retcode) return success if not output else (success, stdout, stderr, retcode)
@ -221,7 +223,25 @@ class Utils():
@staticmethod @staticmethod
def wait_for(cond, timeout, interval=None): def wait_for(cond, timeout, interval=None):
"""Wait until condition expression `cond` is True, up to `timeout` sec """Wait until condition expression `cond` is True, up to `timeout` sec
Parameters
----------
cond : callable
The expression to check condition
(should return equivalent to bool True if wait successful).
timeout : float or callable
The time out for end of wait
(in seconds or callable that returns True if timeout occurred).
interval : float (optional)
Polling start interval for wait cycle in seconds.
Returns
-------
variable
The return value of the last call of `cond`,
logical False (or None, 0, etc) if timeout occurred.
""" """
#logSys.log(5, " wait for %r, tout: %r / %r", cond, timeout, interval)
ini = 1 # to delay initializations until/when necessary ini = 1 # to delay initializations until/when necessary
while True: while True:
ret = cond() ret = cond()
@ -229,10 +249,14 @@ class Utils():
return ret return ret
if ini: if ini:
ini = stm = 0 ini = stm = 0
time0 = time.time() + timeout if not callable(timeout):
time0 = time.time() + timeout
timeout_expr = lambda: time.time() > time0
else:
timeout_expr = timeout
if not interval: if not interval:
interval = Utils.DEFAULT_SLEEP_INTERVAL interval = Utils.DEFAULT_SLEEP_INTERVAL
if time.time() > time0: if timeout_expr():
break break
stm = min(stm + interval, Utils.DEFAULT_SLEEP_TIME) stm = min(stm + interval, Utils.DEFAULT_SLEEP_TIME)
time.sleep(stm) time.sleep(stm)

View File

@ -353,8 +353,8 @@ class CommandActionTest(LogCaptureTestCase):
# timeout as long as pid-file was not created, but max 5 seconds # timeout as long as pid-file was not created, but max 5 seconds
def getnasty_tout(): def getnasty_tout():
return ( return (
getnastypid() is None getnastypid() is not None
and time.time() - stime <= 5 or time.time() - stime > 5
) )
def getnastypid(): def getnastypid():

View File

@ -239,6 +239,7 @@ def initTests(opts):
# (prevent long sleeping during test cases ... less time goes to sleep): # (prevent long sleeping during test cases ... less time goes to sleep):
Utils.DEFAULT_SLEEP_TIME = 0.0025 Utils.DEFAULT_SLEEP_TIME = 0.0025
Utils.DEFAULT_SLEEP_INTERVAL = 0.0005 Utils.DEFAULT_SLEEP_INTERVAL = 0.0005
Utils.DEFAULT_SHORT_INTERVAL = 0.0001
def F2B_SkipIfFast(): def F2B_SkipIfFast():
raise unittest.SkipTest('Skip test because of "--fast"') raise unittest.SkipTest('Skip test because of "--fast"')
unittest.F2B.SkipIfFast = F2B_SkipIfFast unittest.F2B.SkipIfFast = F2B_SkipIfFast
@ -246,6 +247,7 @@ def initTests(opts):
# smaller inertance inside test-cases (litle speedup): # smaller inertance inside test-cases (litle speedup):
Utils.DEFAULT_SLEEP_TIME = 0.25 Utils.DEFAULT_SLEEP_TIME = 0.25
Utils.DEFAULT_SLEEP_INTERVAL = 0.025 Utils.DEFAULT_SLEEP_INTERVAL = 0.025
Utils.DEFAULT_SHORT_INTERVAL = 0.0005
# sleep intervals are large - use replacement for sleep to check time to sleep: # sleep intervals are large - use replacement for sleep to check time to sleep:
_org_sleep = time.sleep _org_sleep = time.sleep
def _new_sleep(v): def _new_sleep(v):