bisect-kit: limit DUT allocation to 9 minutes by default
The bisector pubsub ACK deadline is 10 minutes. More allocations will
start if previous allocation is not finished in 10 minutes because of no
ACK. So set 9 miniutes as default limit.
BUG=b:143663659, b:140700328
TEST=run cros_helper.py allocate_dut manually
Change-Id: I7099f1568ffff0c4689ab7cd56aff7eb2a1cb291
Reviewed-on: https://chromium-review.googlesource.com/1894776
Tested-by: Kuang-che Wu <kcwu@chromium.org>
Commit-Ready: Kuang-che Wu <kcwu@chromium.org>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Kuang-che Wu <kcwu@chromium.org>
diff --git a/bisect_kit/util.py b/bisect_kit/util.py
index 263e4b2..2639183 100644
--- a/bisect_kit/util.py
+++ b/bisect_kit/util.py
@@ -19,6 +19,14 @@
logger = logging.getLogger(__name__)
+class TimeoutExpired(Exception):
+ """Timeout expired.
+
+ This may be raised by blocking calls like Popen.wait(), check_call(),
+ check_output(), etc.
+ """
+
+
class Popen(object):
"""Wrapper of subprocess.Popen. Support output logging.
@@ -88,15 +96,32 @@
self.queue.put((where, line))
self.queue.put((where, ''))
- def wait(self):
+ def wait(self, timeout=None):
"""Waits child process.
Returns:
return code.
"""
+ t0 = time.time()
ended = 0
while ended < 2:
- where, line = self.queue.get()
+ if timeout is not None:
+ try:
+ remaining_time = timeout - (time.time() - t0)
+ if remaining_time > 0:
+ where, line = self.queue.get(block=True, timeout=remaining_time)
+ else:
+ # We follow queue.get's behavior to raise queue.Empty, so it's
+ # always queue.Empty when time is up, no matter remaining_time is
+ # negative or positive.
+ raise queue.Empty
+ except queue.Empty:
+ logger.debug('child process time out (%.1f seconds), kill it',
+ timeout)
+ self.p.kill()
+ raise TimeoutExpired
+ else:
+ where, line = self.queue.get(block=True)
# line includes '\n', will be '' if EOF.
if not line:
ended += 1
@@ -141,8 +166,13 @@
Returns:
Exit code of sub-process.
"""
+ timeout = kwargs.get('timeout')
+ # TODO(kcwu): let current function capture this optional parameter after
+ # migrated to python3
+ if 'timeout' in kwargs:
+ del kwargs['timeout']
p = Popen(args, **kwargs)
- return p.wait()
+ return p.wait(timeout=timeout)
def check_output(*args, **kwargs):
@@ -161,8 +191,13 @@
def collect_stdout(line):
stdout_lines.append(line)
+ timeout = kwargs.get('timeout')
+ # TODO(kcwu): let current function capture this optional parameter after
+ # migrated to python3
+ if 'timeout' in kwargs:
+ del kwargs['timeout']
p = Popen(args, stdout_callback=collect_stdout, **kwargs)
- p.wait()
+ p.wait(timeout=timeout)
stdout = ''.join(stdout_lines)
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, args, stdout)
@@ -178,8 +213,13 @@
Raises:
subprocess.CalledProcessError if the exit code is non-zero.
"""
+ timeout = kwargs.get('timeout')
+ # TODO(kcwu): let current function capture this optional parameter after
+ # migrated to python3
+ if 'timeout' in kwargs:
+ del kwargs['timeout']
p = Popen(args, **kwargs)
- p.wait()
+ p.wait(timeout=timeout)
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, args)