in src/buildstream/_scheduler/jobs/job.py [0:0]
def child_action(self):
# Set the global message handler in this child
# process to forward messages to the parent process
self._messenger.setup_new_action_context(
self.action_name, self._message_element_name, self._message_element_key
)
with ExitStack() as stack:
# Time, log and and run the action function
#
timeinfo = stack.enter_context(self._messenger.timed_suspendable())
try:
filename = (
stack.enter_context(
self._messenger.recorded_messages(self._logfile, self._scheduler.context.logdir)
)
if self._logfile
else None
)
except Exception as e: # pylint: disable=broad-except
elapsed = datetime.datetime.now() - timeinfo.start_time
self.message(
MessageType.ERROR,
"Error opening log file: {}".format(e),
elapsed=elapsed,
detail=traceback.format_exc(),
)
self._thread_id = None
return _ReturnCode.PERM_FAIL, None
try:
self.message(MessageType.START, self.action_name, logfile=filename)
with self._terminate_lock:
self._thread_id = threading.current_thread().ident
if self._should_terminate:
return _ReturnCode.TERMINATED, None
try:
# Try the task action
result = self.child_process() # pylint: disable=assignment-from-no-return
except SkipJob as e:
elapsed = datetime.datetime.now() - timeinfo.start_time
self.message(MessageType.SKIPPED, str(e), elapsed=elapsed, logfile=filename)
# Alert parent of skip by return code
return _ReturnCode.SKIPPED, None
except BstError as e:
elapsed = datetime.datetime.now() - timeinfo.start_time
retry_flag = e.temporary
if retry_flag and (self._tries <= self._max_retries):
self.message(
MessageType.FAIL,
"Try #{} failed, retrying".format(self._tries),
elapsed=elapsed,
logfile=filename,
)
else:
self.message(
MessageType.FAIL,
str(e),
elapsed=elapsed,
detail=e.detail,
logfile=filename,
sandbox=e.sandbox,
)
# Report the exception to the parent (for internal testing purposes)
set_last_task_error(e.domain, e.reason)
# Set return code based on whether or not the error was temporary.
#
return _ReturnCode.FAIL if retry_flag else _ReturnCode.PERM_FAIL, None
except Exception: # pylint: disable=broad-except
# If an unhandled (not normalized to BstError) occurs, that's a bug,
# send the traceback and formatted exception back to the frontend
# and print it to the log file.
#
elapsed = datetime.datetime.now() - timeinfo.start_time
detail = "An unhandled exception occured:\n\n{}".format(traceback.format_exc())
self.message(MessageType.BUG, self.action_name, elapsed=elapsed, detail=detail, logfile=filename)
# Unhandled exceptions should permenantly fail
return _ReturnCode.PERM_FAIL, None
else:
# No exception occurred in the action
elapsed = datetime.datetime.now() - timeinfo.start_time
self.message(MessageType.SUCCESS, self.action_name, elapsed=elapsed, logfile=filename)
# Shutdown needs to stay outside of the above context manager,
# make sure we dont try to handle SIGTERM while the process
# is already busy in sys.exit()
return _ReturnCode.OK, result
finally:
self._thread_id = None
except TerminateException:
self._thread_id = None
return _ReturnCode.TERMINATED, None