def handle_task(self, cntx, **kwargs): """Handle the execution of the workbook task. :param cntx: a request context dict :type cntx: dict :param kwargs: a dict of method arguments :type kwargs: dict """ try: task = kwargs.get('task', None) if not task: raise Exception('No task is provided to the executor.') LOG.info("Received a task: %s" % task) db_task = db_api.task_get(task['workbook_name'], task['execution_id'], task['id']) db_exec = db_api.execution_get(task['workbook_name'], task['execution_id']) if not db_exec or not db_task: return if db_exec['state'] != states.RUNNING or \ db_task['state'] != states.IDLE: return self._do_task_action(db_task) db_api.task_update(task['workbook_name'], task['execution_id'], task['id'], {'state': states.RUNNING}) except Exception as exc: LOG.exception(exc) self._handle_task_error(task, exc)
def _run_task(cls, task): action = a_f.create_action(task) LOG.info("Task is started - %s" % task['name']) if a_h.is_task_synchronous(task): try: state, result = states.SUCCESS, action.run() except exc.ActionException: state, result = states.ERROR, None cls.convey_task_result(task['workbook_name'], task['execution_id'], task['id'], state, result) else: try: action.run() db_api.task_update(task['workbook_name'], task['execution_id'], task['id'], {'state': states.RUNNING}) except exc.ActionException: cls.convey_task_result(task['workbook_name'], task['execution_id'], task['id'], states.ERROR, None)
def prepare_tasks(tasks, context): for task in tasks: # TODO(rakhmerov): Inbound context should be a merge of outbound # contexts of task dependencies, if any. task['in_context'] = context task['parameters'] = evaluate_task_parameters(task, context) db_api.task_update(task['workbook_name'], task['execution_id'], task['id'], {'in_context': task['in_context'], 'parameters': task['parameters']})
def run_delayed_task(): """ Runs the delayed task. Performs all the steps required to setup a task to run which are not already done. This is mostly code copied over from convey_task_result. """ db_api.start_tx() try: workbook_name = task['workbook_name'] execution_id = task['execution_id'] execution = db_api.execution_get(workbook_name, execution_id) # Change state from DELAYED to IDLE to unblock processing. WORKFLOW_TRACE.info("Task '%s' [%s -> %s]" % (task['name'], task['state'], states.IDLE)) db_task = db_api.task_update(workbook_name, execution_id, task['id'], {"state": states.IDLE}) task_to_start = [db_task] data_flow.prepare_tasks(task_to_start, outbound_context) db_api.commit_tx() finally: db_api.end_tx() if not states.is_stopped_or_finished(execution["state"]): cls._run_tasks(task_to_start)
def _update_task(cls, workbook, task, state, task_output): """ Update the task with the runtime information. The outbound_context for this task is also calculated. :return: task, outbound_context. task is the updated task and computed outbound context. """ workbook_name = task['workbook_name'] execution_id = task['execution_id'] task_spec = workbook.tasks.get(task["name"]) task_runtime_context = task["task_runtime_context"] # Compute the outbound_context, state and exec_flow_context. outbound_context = data_flow.get_outbound_context(task, task_output) state, task_runtime_context = retry.get_task_runtime( task_spec, state, outbound_context, task_runtime_context) # Update the task. update_values = {"state": state, "output": task_output, "task_runtime_context": task_runtime_context} task = db_api.task_update(workbook_name, execution_id, task["id"], update_values) return task, outbound_context
def _update_task(cls, workbook, task, state, task_output): """ Update the task with the runtime information. The outbound_context for this task is also calculated. :return: task, outbound_context. task is the updated task and computed outbound context. """ workbook_name = task['workbook_name'] execution_id = task['execution_id'] task_spec = workbook.tasks.get(task["name"]) task_runtime_context = task["task_runtime_context"] # Compute the outbound_context, state and exec_flow_context. outbound_context = data_flow.get_outbound_context(task, task_output) state, task_runtime_context = retry.get_task_runtime( task_spec, state, outbound_context, task_runtime_context) # Update the task. update_values = { "state": state, "output": task_output, "task_runtime_context": task_runtime_context } task = db_api.task_update(workbook_name, execution_id, task["id"], update_values) return task, outbound_context
def prepare_tasks(tasks, context, workbook): results = [] for task in tasks: # TODO(rakhmerov): Inbound context should be a merge of # outbound contexts of task dependencies, if any. action_params = evaluate_task_parameters(task, context) db_api.task_update(task['id'], {'state': states.RUNNING, 'in_context': context, 'parameters': action_params}) # Get action name. Unwrap ad-hoc and reevaluate params if # necessary. action_name = wb_task.TaskSpec(task['task_spec'])\ .get_full_action_name() openstack_ctx = context.get('openstack') if not a_f.get_action_class(action_name): # If action is not found in registered actions try to find # ad-hoc action definition. if openstack_ctx is not None: action_params.update({'openstack': openstack_ctx}) action = a_f.resolve_adhoc_action_name(workbook, action_name) if not action: msg = 'Unknown action [workbook=%s, action=%s]' % \ (workbook, action_name) raise exc.ActionException(msg) action_params = a_f.convert_adhoc_action_params(workbook, action_name, action_params) action_name = action if _has_action_context_param(a_f.get_action_class(action_name)): action_params[_ACTION_CTX_PARAM] = \ _get_action_context(task, openstack_ctx) results.append((task['id'], action_name, action_params)) return results
def handle_task(self, cntx, **kwargs): """Handle the execution of the workbook task. :param cntx: a request context dict :type cntx: dict :param kwargs: a dict of method arguments :type kwargs: dict """ try: task = kwargs.get('task', None) if not task: raise Exception('No task is provided to the executor.') LOG.info("Received a task: %s" % task) db_task = db_api.task_get(task['workbook_name'], task['execution_id'], task['id']) db_exec = db_api.execution_get(task['workbook_name'], task['execution_id']) if not db_exec or not db_task: return if db_exec['state'] != states.RUNNING or \ db_task['state'] != states.IDLE: return # Update the state to running before performing action. The # do_task_action assigns state to the task which is the appropriate # value to preserve. WORKFLOW_TRACE.info("Task '%s' [%s -> %s]" % (db_task['name'], db_task['state'], states.RUNNING)) db_api.task_update(task['workbook_name'], task['execution_id'], task['id'], {'state': states.RUNNING}) self._do_task_action(db_task) except Exception as e: LOG.exception(e) self._handle_task_error(task, e)
def handle_task(self, cntx, **kwargs): """Handle the execution of the workbook task. :param cntx: a request context dict :type cntx: dict :param kwargs: a dict of method arguments :type kwargs: dict """ try: task = kwargs.get('task', None) if not task: raise Exception('No task is provided to the executor.') LOG.info("Received a task: %s" % task) db_task = db_api.task_get(task['workbook_name'], task['execution_id'], task['id']) db_exec = db_api.execution_get(task['workbook_name'], task['execution_id']) if not db_exec or not db_task: return if db_exec['state'] != states.RUNNING or \ db_task['state'] != states.IDLE: return # Update the state to running before performing action. The # do_task_action assigns state to the task which is the appropriate # value to preserve. WORKFLOW_TRACE.info( "Task '%s' [%s -> %s]" % (db_task['name'], db_task['state'], states.RUNNING)) db_api.task_update(task['workbook_name'], task['execution_id'], task['id'], {'state': states.RUNNING}) self._do_task_action(db_task) except Exception as e: LOG.exception(e) self._handle_task_error(task, e)
def _handle_task_error(self, task, exception): """Handle exception from the task execution. :param task: the task corresponding to the exception :type task: dict :param exception: an exception thrown during the execution of the task :type exception: Exception """ try: db_api.start_tx() try: db_api.execution_update(task['execution_id'], {'state': states.ERROR}) db_api.task_update(task['id'], {'state': states.ERROR}) db_api.commit_tx() finally: db_api.end_tx() except Exception as e: LOG.exception(e)
def convey_task_result(cls, workbook_name, execution_id, task_id, state, result): db_api.start_tx() workbook = cls._get_workbook(workbook_name) try: #TODO(rakhmerov): validate state transition task = db_api.task_get(workbook_name, execution_id, task_id) task_output = data_flow.get_task_output(task, result) # Update task state. task = db_api.task_update(workbook_name, execution_id, task_id, {"state": state, "output": task_output}) execution = db_api.execution_get(workbook_name, execution_id) # Calculate task outbound context. outbound_context = data_flow.get_outbound_context(task) cls._create_next_tasks(task, workbook) # Determine what tasks need to be started. tasks = db_api.tasks_get(workbook_name, execution_id) new_exec_state = cls._determine_execution_state(execution, tasks) if execution['state'] != new_exec_state: execution = \ db_api.execution_update(workbook_name, execution_id, { "state": new_exec_state }) LOG.info("Changed execution state: %s" % execution) tasks_to_start = workflow.find_resolved_tasks(tasks) data_flow.prepare_tasks(tasks_to_start, outbound_context) db_api.commit_tx() except Exception as e: raise exc.EngineException("Failed to create necessary DB objects:" " %s" % e) finally: db_api.end_tx() if states.is_stopped_or_finished(execution["state"]): return task if tasks_to_start: cls._run_tasks(tasks_to_start) return task
def _handle_task_error(self, task, exception): """Handle exception from the task execution. :param task: the task corresponding to the exception :type task: dict :param exception: an exception thrown during the execution of the task :type exception: Exception """ try: db_api.start_tx() try: db_api.execution_update(task['workbook_name'], task['execution_id'], {'state': states.ERROR}) db_api.task_update(task['workbook_name'], task['execution_id'], task['id'], {'state': states.ERROR}) db_api.commit_tx() finally: db_api.end_tx() except Exception as e: LOG.exception(e)
def _do_task_action(self, task): """Executes the action defined by the task and return result. :param task: a task definition :type task: dict """ LOG.info("Starting task action [task_id=%s, " "action='%s', service='%s'" % (task['id'], task['task_spec']['action'], task['service_spec'])) action = a_f.create_action(task) if a_h.is_task_synchronous(task): try: state, result = states.SUCCESS, action.run() except exc.ActionException: state, result = states.ERROR, None engine.convey_task_result(task['workbook_name'], task['execution_id'], task['id'], state, result) else: try: action.run() db_api.task_update(task['workbook_name'], task['execution_id'], task['id'], {'state': states.RUNNING}) except exc.ActionException: engine.convey_task_result(task['workbook_name'], task['execution_id'], task['id'], states.ERROR, None)