def cancel(self): # Cancel the target workflow. wf_svc.request_cancellation(self.execution) # 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 (child_ex.runner['name'] in ac_const.WORKFLOW_RUNNER_TYPES and child_ex.status in ac_const.LIVEACTION_CANCELABLE_STATES): 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, self.liveaction.result, self.liveaction.context )
def test_cancellation(self): # Manually create the liveaction and action execution objects without publishing. wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, TEST_FIXTURES['workflows'][0]) lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.create_request(lv_ac_db) # Request and pre-process the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = wf_svc.request(wf_def, ac_ex_db, st2_ctx) wf_ex_db = self.prep_wf_ex(wf_ex_db) # Manually request task executions. task_route = 0 self.run_workflow_step(wf_ex_db, 'task1', task_route) self.assert_task_running('task2', task_route) # Cancel the workflow when there is still active task(s). wf_ex_db = wf_svc.request_cancellation(ac_ex_db) conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) self.assertEqual(conductor.get_workflow_status(), wf_statuses.CANCELING) self.assertEqual(wf_ex_db.status, wf_statuses.CANCELING) # Manually complete the task and ensure workflow is canceled. self.run_workflow_step(wf_ex_db, 'task2', task_route) self.assert_task_not_started('task3', task_route) conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) self.assertEqual(conductor.get_workflow_status(), wf_statuses.CANCELED) self.assertEqual(wf_ex_db.status, wf_statuses.CANCELED)
def test_cancellation(self): # Manually create the liveaction and action execution objects without publishing. wf_meta = self.get_wf_fixture_meta_data(TEST_PACK_PATH, TEST_FIXTURES["workflows"][0]) lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = ac_svc.create_request(lv_ac_db) # Request and pre-process the workflow execution. wf_def = self.get_wf_def(TEST_PACK_PATH, wf_meta) st2_ctx = self.mock_st2_context(ac_ex_db) wf_ex_db = wf_svc.request(wf_def, ac_ex_db, st2_ctx) wf_ex_db = self.prep_wf_ex(wf_ex_db) # Manually request task executions. task_route = 0 self.run_workflow_step(wf_ex_db, "task1", task_route) self.assert_task_running("task2", task_route) # Cancel the workflow when there is still active task(s). wf_ex_db = wf_svc.request_cancellation(ac_ex_db) conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) self.assertEqual(conductor.get_workflow_status(), wf_statuses.CANCELING) self.assertEqual(wf_ex_db.status, wf_statuses.CANCELING) # Manually complete the task and ensure workflow is canceled. self.run_workflow_step(wf_ex_db, "task2", task_route) self.assert_task_not_started("task3", task_route) conductor, wf_ex_db = wf_svc.refresh_conductor(str(wf_ex_db.id)) self.assertEqual(conductor.get_workflow_status(), wf_statuses.CANCELED) self.assertEqual(wf_ex_db.status, wf_statuses.CANCELED)
def cancel(self): result = None # Try to cancel the target workflow execution. try: 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. %s' result = {'error': msg % str(ex), 'traceback': ''.join(traceback.format_tb(tb, 20))} msg = '[%s] Error encountered when canceling workflow execution.' LOG.exception(msg, str(self.execution.id)) # 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 )