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. LOG.error('[%s] Unknown error while processing %s execution. %s: %s', wf_ex_db.action_execution, msg_type, exception.__class__.__name__, str(exception)) # 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 = '[%s] Unknown error while processing %s execution. Failing task execution "%s".' LOG.error(msg, wf_ex_db.action_execution, msg_type, task_ex_id) 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 = '[%s] Unknown error while processing %s execution. Failing workflow execution "%s".' LOG.error(msg, wf_ex_db.action_execution, msg_type, wf_ex_id) wf_svc.fail_workflow_execution(wf_ex_id, exception, task=task)
def process(self, wf_ex_db): # Refresh record from the database in case the request is in the queue for too long. conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) # Continue if workflow is still active. if conductor.get_workflow_state() not in states.COMPLETED_STATES: # Set workflow to running state. conductor.set_workflow_state(states.RUNNING) # Identify the next set of tasks to execute. next_tasks = conductor.get_next_tasks() # If there is no new tasks, update execution records to handle possible completion. if not next_tasks: # Update workflow execution and related liveaction and action execution. wf_svc.update_execution_records(wf_ex_db, conductor) # If workflow execution is no longer active, then stop processing here. if wf_ex_db.status in states.COMPLETED_STATES: return # Iterate while there are next tasks identified for processing. In the case for # task with no action execution defined, the task execution will complete # immediately with a new set of tasks available. while next_tasks: # Mark the tasks as running in the task flow before actual task execution. for task in next_tasks: conductor.update_task_flow(task['id'], states.RUNNING) # Update workflow execution and related liveaction and action execution. wf_svc.update_execution_records(wf_ex_db, conductor) # If workflow execution is no longer active, then stop processing here. if wf_ex_db.status in states.COMPLETED_STATES: break # Request task execution for the tasks. for task in next_tasks: try: task_id, task_spec, task_ctx = task['id'], task[ 'spec'], task['ctx'] st2_ctx = {'execution_id': wf_ex_db.action_execution} wf_svc.request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx) except Exception as e: wf_svc.fail_workflow_execution(str(wf_ex_db.id), e, task_id=task['id']) return # Identify the next set of tasks to execute. conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) next_tasks = conductor.get_next_tasks()
def process(self, wf_ex_db): # Refresh record from the database in case the request is in the queue for too long. conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) # Continue if workflow is still active. if conductor.get_workflow_state() not in states.COMPLETED_STATES: # Set workflow to running state. conductor.set_workflow_state(states.RUNNING) # Identify the next set of tasks to execute. next_tasks = conductor.get_next_tasks() # If there is no new tasks, update execution records to handle possible completion. if not next_tasks: # Update workflow execution and related liveaction and action execution. wf_svc.update_execution_records(wf_ex_db, conductor) # If workflow execution is no longer active, then stop processing here. if wf_ex_db.status in states.COMPLETED_STATES: return # Iterate while there are next tasks identified for processing. In the case for # task with no action execution defined, the task execution will complete # immediately with a new set of tasks available. while next_tasks: # Mark the tasks as running in the task flow before actual task execution. for task in next_tasks: conductor.update_task_flow(task['id'], states.RUNNING) # Update workflow execution and related liveaction and action execution. wf_svc.update_execution_records(wf_ex_db, conductor) # If workflow execution is no longer active, then stop processing here. if wf_ex_db.status in states.COMPLETED_STATES: break # Request task execution for the tasks. for task in next_tasks: try: task_id, task_spec, task_ctx = task['id'], task['spec'], task['ctx'] st2_ctx = {'execution_id': wf_ex_db.action_execution} wf_svc.request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx) except Exception as e: wf_svc.fail_workflow_execution(str(wf_ex_db.id), e, task_id=task['id']) return # Identify the next set of tasks to execute. conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) next_tasks = conductor.get_next_tasks()
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): iteration = 0 wf_ac_ex_id = wf_ex_db.action_execution LOG.info('[%s] Processing request for workflow execution.', wf_ac_ex_id) # Refresh record from the database in case the request is in the queue for too long. conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) # Continue if workflow is still active and set workflow to running state. if conductor.get_workflow_state() not in states.COMPLETED_STATES: LOG.info( '[%s] Requesting conductor to start running workflow execution.', wf_ac_ex_id) conductor.request_workflow_state(states.RUNNING) # Identify the next set of tasks to execute. msg = '[%s] Identifying next set (%s) of tasks for workflow execution in state "%s".' LOG.info(msg, wf_ac_ex_id, str(iteration), conductor.get_workflow_state()) LOG.debug('[%s] %s', wf_ac_ex_id, conductor.serialize()) next_tasks = conductor.get_next_tasks() # If there is no new tasks, update execution records to handle possible completion. if not next_tasks: # Update workflow execution and related liveaction and action execution. LOG.info('[%s] No tasks identified to execute next.', wf_ac_ex_id) wf_svc.update_execution_records(wf_ex_db, conductor) # If workflow execution is no longer active, then stop processing here. if wf_ex_db.status in states.COMPLETED_STATES: msg = '[%s] Workflow execution is in completed state "%s".' LOG.info(msg, wf_ac_ex_id, wf_ex_db.status) return # Iterate while there are next tasks identified for processing. In the case for # task with no action execution defined, the task execution will complete # immediately with a new set of tasks available. while next_tasks: msg = '[%s] Identified the following set of tasks to execute next: %s' LOG.info(msg, wf_ac_ex_id, ', '.join([task['id'] for task in next_tasks])) # Mark the tasks as running in the task flow before actual task execution. for task in next_tasks: msg = '[%s] Mark task "%s" in conductor as running.' LOG.info(msg, wf_ac_ex_id, task['id']) ac_ex_event = events.ActionExecutionEvent(states.RUNNING) conductor.update_task_flow(task['id'], ac_ex_event) # Update workflow execution and related liveaction and action execution. wf_svc.update_execution_records(wf_ex_db, conductor) # If workflow execution is no longer active, then stop processing here. if wf_ex_db.status in states.COMPLETED_STATES: msg = '[%s] Workflow execution is in completed state "%s".' LOG.info(msg, wf_ac_ex_id, wf_ex_db.status) break # Request task execution for the tasks. for task in next_tasks: try: LOG.info('[%s] Requesting execution for task "%s".', wf_ac_ex_id, task['id']) task_id, task_spec, task_ctx = task['id'], task[ 'spec'], task['ctx'] st2_ctx = {'execution_id': wf_ex_db.action_execution} wf_svc.request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx) except Exception as e: LOG.exception('[%s] Failed task execution for "%s".', wf_ac_ex_id, task['id']) wf_svc.fail_workflow_execution(str(wf_ex_db.id), e, task_id=task['id']) return # Identify the next set of tasks to execute. iteration += 1 conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) msg = '[%s] Identifying next set (%s) of tasks for workflow execution in state "%s".' LOG.info(msg, wf_ac_ex_id, str(iteration), conductor.get_workflow_state()) LOG.debug('[%s] %s', wf_ac_ex_id, conductor.serialize()) next_tasks = conductor.get_next_tasks() if not next_tasks: LOG.info('[%s] No tasks identified to execute next.', wf_ac_ex_id)