remove paver timeout decorator
This commit is contained in:
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user