remove paver timeout decorator

This commit is contained in:
Stuart Young
2018-10-01 10:58:56 -04:00
parent b4f2e8ad72
commit 10cfd3434e
4 changed files with 17 additions and 124 deletions

View File

@@ -1,29 +0,0 @@
""" Tests for the utility decorators for Paver """
import time
import pytest
from pavelib.utils.decorators import (
timeout, TimeoutException
)
def test_function_under_timeout():
@timeout(2)
def sample_function_1():
return "sample text"
value = sample_function_1()
assert value == "sample text"
def test_function_over_timeout():
@timeout(0.1)
def sample_function_2():
time.sleep(1)
return "sample text"
with pytest.raises(TimeoutException):
sample_function_2()

View File

@@ -92,13 +92,10 @@ class TestPaverNodeInstall(PaverTestCase):
an npm install error ("cb() never called!"). Test that we can handle
this kind of failure. For more info see TE-1767.
"""
with patch('pavelib.utils.decorators.timeout') as _timeout_patch:
_timeout_patch.return_value = lambda x: x
reload(pavelib.prereqs)
with patch('subprocess.Popen') as _mock_popen:
_mock_popen.side_effect = fail_on_npm_install
with self.assertRaises(BuildFailure):
pavelib.prereqs.node_prereqs_installation()
with patch('subprocess.Popen') as _mock_popen:
_mock_popen.side_effect = fail_on_npm_install
with self.assertRaises(BuildFailure):
pavelib.prereqs.node_prereqs_installation()
# npm install will be called twice
self.assertEquals(_mock_popen.call_count, 2)
@@ -106,11 +103,8 @@ class TestPaverNodeInstall(PaverTestCase):
"""
Vanilla npm install should only be calling npm install one time
"""
with patch('pavelib.utils.decorators.timeout') as _timeout_patch:
_timeout_patch.return_value = lambda x: x
reload(pavelib.prereqs)
with patch('subprocess.Popen') as _mock_popen:
pavelib.prereqs.node_prereqs_installation()
with patch('subprocess.Popen') as _mock_popen:
pavelib.prereqs.node_prereqs_installation()
# when there's no failure, npm install is only called once
self.assertEquals(_mock_popen.call_count, 1)
@@ -118,11 +112,8 @@ class TestPaverNodeInstall(PaverTestCase):
"""
If there's some other error, only call npm install once, and raise a failure
"""
with patch('pavelib.utils.decorators.timeout') as _timeout_patch:
_timeout_patch.return_value = lambda x: x
reload(pavelib.prereqs)
with patch('subprocess.Popen') as _mock_popen:
_mock_popen.side_effect = unexpected_fail_on_npm_install
with self.assertRaises(BuildFailure):
pavelib.prereqs.node_prereqs_installation()
with patch('subprocess.Popen') as _mock_popen:
_mock_popen.side_effect = unexpected_fail_on_npm_install
with self.assertRaises(BuildFailure):
pavelib.prereqs.node_prereqs_installation()
self.assertEquals(_mock_popen.call_count, 1)

View File

@@ -14,7 +14,6 @@ from paver.easy import BuildFailure, sh, task
from .utils.envs import Env
from .utils.timer import timed
from .utils.decorators import timeout, TimeoutException
PREREQS_STATE_DIR = os.getenv('PREREQ_CACHE_DIR', Env.REPO_ROOT / '.prereqs_cache')
NO_PREREQ_MESSAGE = "NO_PREREQ_INSTALL is set, not installing prereqs"
@@ -129,17 +128,6 @@ def node_prereqs_installation():
Configures npm and installs Node prerequisites
"""
@timeout(limit=600)
def _run_npm_command(npm_command, npm_log_file):
"""
helper function for running the npm installation with a timeout.
The implementation of Paver's `sh` function returns before the forked
actually returns. Using a Popen object so that we can ensure that
the forked process has returned
"""
proc = subprocess.Popen(npm_command, stderr=npm_log_file)
proc.wait()
# NPM installs hang sporadically. Log the installation process so that we
# determine if any packages are chronic offenders.
shard_str = os.getenv('SHARD', None)
@@ -156,15 +144,16 @@ def node_prereqs_installation():
# evinces itself as `cb_error_text` and it ought to disappear when we upgrade
# npm to 3 or higher. TODO: clean this up when we do that.
try:
_run_npm_command(npm_command, npm_log_file)
except TimeoutException:
print "NPM installation took too long. Exiting..."
print "Check {} for more information".format(npm_log_file_path)
sys.exit(1)
# The implementation of Paver's `sh` function returns before the forked
# actually returns. Using a Popen object so that we can ensure that
# the forked process has returned
proc = subprocess.Popen(npm_command, stderr=npm_log_file)
proc.wait()
except BuildFailure, error_text:
if cb_error_text in error_text:
print "npm install error detected. Retrying..."
_run_npm_command(npm_command, npm_log_file)
proc = subprocess.Popen(npm_command, stderr=npm_log_file)
proc.wait()
else:
raise BuildFailure(error_text)
print "Successfully installed NPM packages. Log found at {}".format(

View File

@@ -1,58 +0,0 @@
""" a collection of utililty decorators for paver tasks """
import multiprocessing
from functools import wraps
import psutil
def timeout(limit=60):
"""
kill a function if it has not completed within a specified timeframe
"""
def _handle_function_process(*args, **kwargs):
""" helper function for running a function and getting its output """
queue = kwargs['queue']
function = kwargs['function_to_call']
function_args = args
function_kwargs = kwargs['function_kwargs']
function_output = function(*function_args, **function_kwargs)
queue.put(function_output)
def decorated_function(function):
""" the time-limited function returned by the timeout decorator """
def function_wrapper(*args, **kwargs):
"""
take a function and run it on a separate process, forcing it to
either give up its return value or throw a TimeoutException with
a specified timeframe (in seconds)
"""
queue = multiprocessing.Queue()
args_tuple = tuple(a for a in args)
meta_kwargs = {
'function_to_call': function, 'queue': queue,
'function_kwargs': kwargs
}
function_proc = multiprocessing.Process(
target=_handle_function_process, args=args_tuple, kwargs=meta_kwargs
)
function_proc.start()
function_proc.join(float(limit))
if function_proc.is_alive():
pid = psutil.Process(function_proc.pid)
for child in pid.get_children(recursive=True):
child.terminate()
function_proc.terminate()
raise TimeoutException
function_output = queue.get()
return function_output
return wraps(function)(function_wrapper)
return decorated_function
class TimeoutException(Exception):
pass