def _handle_workflow_return_value(self, wf_ex_db): if wf_ex_db.status in wf_statuses.COMPLETED_STATUSES: status = wf_ex_db.status result = {'output': wf_ex_db.output or None} if wf_ex_db.status in wf_statuses.ABENDED_STATUSES: result['errors'] = wf_ex_db.errors for wf_ex_error in wf_ex_db.errors: msg = 'Workflow execution completed with errors.' wf_svc.update_progress(wf_ex_db, '%s %s' % (msg, str(wf_ex_error)), log=False) LOG.error('[%s] %s', str(self.execution.id), msg, extra=wf_ex_error) return (status, result, self.context) # Set return values. status = ac_const.LIVEACTION_STATUS_RUNNING partial_results = {} ctx = self._construct_context(wf_ex_db) return (status, partial_results, ctx)
def handle_action_execution(self, ac_ex_db): # Exit if action execution is not executed under an orquesta workflow. if not wf_svc.is_action_execution_under_workflow_context(ac_ex_db): return # Get related record identifiers. wf_ex_id = ac_ex_db.context["orquesta"]["workflow_execution_id"] task_ex_id = ac_ex_db.context["orquesta"]["task_execution_id"] # Get execution records for logging purposes. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_id) task_ex_db = wf_db_access.TaskExecution.get_by_id(task_ex_id) msg = 'Action execution "%s" for task "%s" is updated and in "%s" state.' % ( str(ac_ex_db.id), task_ex_db.task_id, ac_ex_db.status, ) wf_svc.update_progress(wf_ex_db, msg) # Skip if task execution is already in completed state. if task_ex_db.status in statuses.COMPLETED_STATUSES: msg = ( 'Action execution "%s" for task "%s", route "%s", is not processed ' 'because task execution "%s" is already in completed state "%s".' % ( str(ac_ex_db.id), task_ex_db.task_id, str(task_ex_db.task_route), str(task_ex_db.id), task_ex_db.status, ) ) wf_svc.update_progress(wf_ex_db, msg) return # Process pending request on the action execution. if ac_ex_db.status == ac_const.LIVEACTION_STATUS_PENDING: wf_svc.handle_action_execution_pending(ac_ex_db) return # Process pause request on the action execution. if ac_ex_db.status == ac_const.LIVEACTION_STATUS_PAUSED: wf_svc.handle_action_execution_pause(ac_ex_db) return # Exit if action execution has not completed yet. if ac_ex_db.status not in ac_const.LIVEACTION_COMPLETED_STATES: return # Apply post run policies. lv_ac_db = lv_db_access.LiveAction.get_by_id(ac_ex_db.liveaction["id"]) pc_svc.apply_post_run_policies(lv_ac_db) # Process completion of the action execution. wf_svc.handle_action_execution_completion(ac_ex_db)
def cancel(self): result = None wf_ex_db = None # Try to cancel the target workflow execution. try: wf_ex_db = wf_svc.request_cancellation(self.execution) # If workflow execution is not found because the action execution is cancelled # before the workflow execution is created or if the workflow execution is # already completed, then ignore the exception and proceed with cancellation. except ( wf_svc_exc.WorkflowExecutionNotFoundException, wf_svc_exc.WorkflowExecutionIsCompletedException, ): pass # If there is an unknown exception, then log the error. Continue with the # cancelation sequence below to cancel children and determine final status. # If we rethrow the exception here, the workflow will be stuck in a canceling # state with no options for user to clean up. It is safer to continue with # the cancel then to revert back to some other statuses because the workflow # execution will be in an unknown state. except Exception: _, ex, tb = sys.exc_info() msg = "Error encountered when canceling workflow execution." LOG.exception("[%s] %s", str(self.execution.id), msg) msg = "Error encountered when canceling workflow execution. %s" wf_svc.update_progress(wf_ex_db, msg % str(ex), log=False) result = { "error": msg % str(ex), "traceback": "".join(traceback.format_tb(tb, 20)), } # Request cancellation of tasks that are workflows and still running. for child_ex_id in self.execution.children: child_ex = ex_db_access.ActionExecution.get(id=child_ex_id) if self.task_cancelable(child_ex): ac_svc.request_cancellation( lv_db_access.LiveAction.get(id=child_ex.liveaction["id"]), self.context.get("user", None), ) status = (ac_const.LIVEACTION_STATUS_CANCELING if ac_svc.is_children_active(self.liveaction.id) else ac_const.LIVEACTION_STATUS_CANCELED) return ( status, result if result else self.liveaction.result, self.liveaction.context, )
def fail_workflow_execution(self, message, exception): # Prepare attributes based on message type. if isinstance(message, wf_db_models.WorkflowExecutionDB): msg_type = 'workflow' wf_ex_db = message wf_ex_id = str(wf_ex_db.id) task = None else: msg_type = 'task' ac_ex_db = message wf_ex_id = ac_ex_db.context['orquesta']['workflow_execution_id'] task_ex_id = ac_ex_db.context['orquesta']['task_execution_id'] wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_id) task_ex_db = wf_db_access.TaskExecution.get_by_id(task_ex_id) task = {'id': task_ex_db.task_id, 'route': task_ex_db.task_route} # Log the error. msg = 'Unknown error while processing %s execution. %s: %s' wf_svc.update_progress( wf_ex_db, msg % (msg_type, exception.__class__.__name__, str(exception)), severity='error') # Fail the task execution so it's marked correctly in the # conductor state to allow for task rerun if needed. if isinstance(message, ex_db_models.ActionExecutionDB): msg = 'Unknown error while processing %s execution. Failing task execution "%s".' wf_svc.update_progress(wf_ex_db, msg % (msg_type, task_ex_id), severity='error') wf_svc.update_task_execution(task_ex_id, ac_const.LIVEACTION_STATUS_FAILED) wf_svc.update_task_state(task_ex_id, ac_const.LIVEACTION_STATUS_FAILED) # Fail the workflow execution. msg = 'Unknown error while processing %s execution. Failing workflow execution "%s".' wf_svc.update_progress(wf_ex_db, msg % (msg_type, wf_ex_id), severity='error') wf_svc.fail_workflow_execution(wf_ex_id, exception, task=task)
def handle_workflow_execution(self, wf_ex_db): # Request the next set of tasks to execute. wf_svc.update_progress(wf_ex_db, 'Processing request for workflow execution.') wf_svc.request_next_tasks(wf_ex_db)