[terminate] Handle GreenletExit exception
R=vadimsh
Bug: 1144073
Change-Id: I5161c3ddb7da19b3e656c903f65c1c24b137a51e
Reviewed-on: https://chromium-review.googlesource.com/c/infra/luci/recipes-py/+/2508692
Reviewed-by: Vadim Shtayura <vadimsh@chromium.org>
Commit-Queue: Vadim Shtayura <vadimsh@chromium.org>
Auto-Submit: Yiwei Zhang <yiwzhang@google.com>
diff --git a/recipe_engine/internal/engine.py b/recipe_engine/internal/engine.py
index 62bc1fc..84f40c6 100644
--- a/recipe_engine/internal/engine.py
+++ b/recipe_engine/internal/engine.py
@@ -37,7 +37,7 @@
from .exceptions import RecipeUsageError, CrashEngine
from .step_runner import Step
from .resource_semaphore import ResourceWaiter
-from .global_shutdown import GLOBAL_SHUTDOWN
+from .global_shutdown import GLOBAL_SHUTDOWN, GLOBAL_TIMEOUT
@attr.s(frozen=True, slots=True, repr=False)
@@ -579,6 +579,12 @@
result.status = common_pb2.INFRA_FAILURE if (
is_infra_failure) else common_pb2.FAILURE
result.summary_markdown = ex.reason
+ except gevent.GreenletExit:
+ result.status = common_pb2.INFRA_FAILURE
+ if GLOBAL_TIMEOUT.ready():
+ result.summary_markdown = 'Recipe timed out'
+ else:
+ result.summary_markdown = 'Recipe was interrupted'
# All other exceptions are reported to the user and are fatal.
except Exception as ex: # pylint: disable=broad-except
diff --git a/recipe_engine/internal/global_shutdown.py b/recipe_engine/internal/global_shutdown.py
index 15792d1..f16d754 100644
--- a/recipe_engine/internal/global_shutdown.py
+++ b/recipe_engine/internal/global_shutdown.py
@@ -45,6 +45,12 @@
# for test mode.
GLOBAL_QUITQUITQUIT = gevent.event.Event()
+# GLOBAL_TIMEOUT is set if recipe terminates because of timeout.
+#
+# This event is only installed for real runs of the recipe; It blocks forever
+# for test mode.
+GLOBAL_TIMEOUT = gevent.event.Event()
+
# UNKILLED_PGIDS is a global set of process groups which haven't been SIGKILL'd
# yet.
#
@@ -88,8 +94,11 @@
if d.soft_deadline:
now = time.time()
if d.soft_deadline > now:
- gevent.wait([GLOBAL_SHUTDOWN], timeout=(d.soft_deadline - now))
- GLOBAL_SHUTDOWN.set()
+ ready = gevent.wait([GLOBAL_SHUTDOWN], timeout=(d.soft_deadline - now))
+ if not ready:
+ # wait ends because of hitting timeout
+ GLOBAL_TIMEOUT.set()
+ GLOBAL_SHUTDOWN.set()
else:
GLOBAL_SHUTDOWN.wait()
LOG.info('Initiating GLOBAL_SHUTDOWN')