def invoke(self): workflow_invocation = self.workflow_invocation remaining_steps = self.progress.remaining_steps() delayed_steps = False for step in remaining_steps: jobs = None try: self.__check_implicitly_dependent_steps(step) jobs = self._invoke_step(step) for job in (util.listify(jobs) or [None]): # Record invocation workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_invocation = workflow_invocation workflow_invocation_step.workflow_step = step workflow_invocation_step.job = job except modules.DelayedWorkflowEvaluation: delayed_steps = True self.progress.mark_step_outputs_delayed(step) if delayed_steps: state = model.WorkflowInvocation.states.READY else: state = model.WorkflowInvocation.states.SCHEDULED workflow_invocation.state = state # All jobs ran successfully, so we can save now self.trans.sa_session.add(workflow_invocation) # Not flushing in here, because web controller may create multiple # invocations. return self.progress.outputs
def test_subworkflow_progress(self): self._setup_workflow(TEST_SUBWORKFLOW_YAML) hda = model.HistoryDatasetAssociation() self._set_previous_progress([ (100, { "output": hda }), (101, UNSCHEDULED_STEP), ]) subworkflow_invocation = self.invocation.create_subworkflow_invocation_for_step( self.invocation.workflow.step_by_index(1)) progress = self._new_workflow_progress() remaining_steps = progress.remaining_steps() (subworkflow_step, subworkflow_invocation_step) = remaining_steps[0] subworkflow_progress = progress.subworkflow_progress( subworkflow_invocation, subworkflow_step, {}) subworkflow = subworkflow_step.subworkflow assert subworkflow_progress.workflow_invocation == subworkflow_invocation assert subworkflow_progress.workflow_invocation.workflow == subworkflow subworkflow_input_step = subworkflow.step_by_index(0) subworkflow_invocation_step = model.WorkflowInvocationStep() subworkflow_invocation_step.workflow_step_id = subworkflow_input_step.id subworkflow_invocation_step.state = 'new' subworkflow_invocation_step.workflow_step = subworkflow_input_step subworkflow_progress.set_outputs_for_input(subworkflow_invocation_step) subworkflow_cat_step = subworkflow.step_by_index(1) assert hda is subworkflow_progress.replacement_for_tool_input( subworkflow_cat_step, MockInput(), "input1", )
def _invocation_step(self, index): if index < len(self.invocation.steps): return self.invocation.steps[index] else: workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_step = self._step(index) return workflow_invocation_step
def invoke(self): workflow_invocation = model.WorkflowInvocation() workflow_invocation.workflow = self.workflow # Web controller will populate state on each step before calling # invoke but not API controller. More work should be done to further # harmonize these methods going forward if possible - if possible # moving more web controller logic here. state_populated = not self.workflow.steps or hasattr( self.workflow.steps[0], "state") if not state_populated: self._populate_state() for step in self.workflow.steps: jobs = self._invoke_step(step) for job in util.listify(jobs): # Record invocation workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_invocation = workflow_invocation workflow_invocation_step.workflow_step = step workflow_invocation_step.job = job # All jobs ran successfully, so we can save now self.trans.sa_session.add(workflow_invocation) # Not flushing in here, because web controller may create multiple # invokations. return self.outputs
def invoke( self ): workflow_invocation = self.workflow_invocation maximum_duration = getattr( self.trans.app.config, "maximum_workflow_invocation_duration", -1 ) if maximum_duration > 0 and workflow_invocation.seconds_since_created > maximum_duration: log.debug("Workflow invocation [%s] exceeded maximum number of seconds allowed for scheduling [%s], failing." % (workflow_invocation.id, maximum_duration)) workflow_invocation.state = model.WorkflowInvocation.states.FAILED # All jobs ran successfully, so we can save now self.trans.sa_session.add( workflow_invocation ) # Not flushing in here, because web controller may create multiple # invocations. return self.progress.outputs remaining_steps = self.progress.remaining_steps() delayed_steps = False for step in remaining_steps: step_delayed = False step_timer = ExecutionTimer() jobs = None try: self.__check_implicitly_dependent_steps(step) # TODO: step may fail to invoke, do something about that. jobs = self._invoke_step( step ) for job in (util.listify( jobs ) or [None]): # Record invocation workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_invocation = workflow_invocation workflow_invocation_step.workflow_step = step # Job may not be generated in this thread if bursting is enabled # https://github.com/galaxyproject/galaxy/issues/2259 if job: workflow_invocation_step.job_id = job.id except modules.DelayedWorkflowEvaluation: step_delayed = delayed_steps = True self.progress.mark_step_outputs_delayed( step ) except Exception: log.exception( "Failed to schedule %s, problem occurred on %s.", self.workflow_invocation.workflow.log_str(), step.log_str(), ) raise step_verb = "invoked" if not step_delayed else "delayed" log.debug("Workflow step %s of invocation %s %s %s" % (step.id, workflow_invocation.id, step_verb, step_timer)) if delayed_steps: state = model.WorkflowInvocation.states.READY else: state = model.WorkflowInvocation.states.SCHEDULED workflow_invocation.state = state # All jobs ran successfully, so we can save now self.trans.sa_session.add( workflow_invocation ) # Not flushing in here, because web controller may create multiple # invocations. return self.progress.outputs
def _set_previous_progress(self, outputs_dict): for step_id, step_value in outputs_dict.items(): if step_value is not UNSCHEDULED_STEP: self.progress[step_id] = step_value workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_step_id = step_id self.invocation.steps.append(workflow_invocation_step) workflow_invocation_step_state = model.WorkflowRequestStepState() workflow_invocation_step_state.workflow_step_id = step_id workflow_invocation_step_state.value = True self.invocation.step_states.append(workflow_invocation_step_state)
def _set_previous_progress(self, outputs): for i, (step_id, step_value) in enumerate(outputs): if step_value is not UNSCHEDULED_STEP: self.progress[step_id] = step_value workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_step_id = step_id workflow_invocation_step.state = 'scheduled' workflow_invocation_step.workflow_step = self._step(i) self.assertEqual(step_id, self._step(i).id) # workflow_invocation_step.workflow_invocation = self.invocation self.invocation.steps.append(workflow_invocation_step) workflow_invocation_step_state = model.WorkflowRequestStepState() workflow_invocation_step_state.workflow_step_id = step_id workflow_invocation_step_state.value = True self.invocation.step_states.append(workflow_invocation_step_state)
def invoke(self): workflow_invocation = self.workflow_invocation remaining_steps = self.progress.remaining_steps() delayed_steps = False for step in remaining_steps: step_delayed = False step_timer = ExecutionTimer() jobs = None try: self.__check_implicitly_dependent_steps(step) # TODO: step may fail to invoke, do something about that. jobs = self._invoke_step(step) for job in (util.listify(jobs) or [None]): # Record invocation workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_invocation = workflow_invocation workflow_invocation_step.workflow_step = step workflow_invocation_step.job = job except modules.DelayedWorkflowEvaluation: step_delayed = delayed_steps = True self.progress.mark_step_outputs_delayed(step) except Exception: log.exception( "Failed to schedule %s, problem occurred on %s.", self.workflow_invocation.workflow.log_str(), step.log_str(), ) raise step_verb = "invoked" if not step_delayed else "delayed" log.debug("Workflow step %s of invocation %s %s %s" % (step.id, workflow_invocation.id, step_verb, step_timer)) if delayed_steps: state = model.WorkflowInvocation.states.READY else: state = model.WorkflowInvocation.states.SCHEDULED workflow_invocation.state = state # All jobs ran successfully, so we can save now self.trans.sa_session.add(workflow_invocation) # Not flushing in here, because web controller may create multiple # invocations. return self.progress.outputs
def invoke( self ): workflow_invocation = self.workflow_invocation remaining_steps = self.progress.remaining_steps() for step in remaining_steps: jobs = self._invoke_step( step ) for job in util.listify( jobs ): # Record invocation workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_invocation = workflow_invocation workflow_invocation_step.workflow_step = step workflow_invocation_step.job = job # All jobs ran successfully, so we can save now self.trans.sa_session.add( workflow_invocation ) # Not flushing in here, because web controller may create multiple # invocations. return self.progress.outputs
def test_workflows(self): model = self.model user = model.User( email="*****@*****.**", password="******" ) def workflow_from_steps(steps): stored_workflow = model.StoredWorkflow() stored_workflow.user = user workflow = model.Workflow() workflow.steps = steps workflow.stored_workflow = stored_workflow return workflow child_workflow = workflow_from_steps([]) self.persist(child_workflow) workflow_step_1 = model.WorkflowStep() workflow_step_1.order_index = 0 workflow_step_1.type = "data_input" workflow_step_2 = model.WorkflowStep() workflow_step_2.order_index = 1 workflow_step_2.type = "subworkflow" workflow_step_2.subworkflow = child_workflow workflow_step_1.get_or_add_input("moo1") workflow_step_1.get_or_add_input("moo2") workflow_step_2.get_or_add_input("moo") workflow_step_1.add_connection("foo", "cow", workflow_step_2) workflow = workflow_from_steps([workflow_step_1, workflow_step_2]) self.persist(workflow) workflow_id = workflow.id annotation = model.WorkflowStepAnnotationAssociation() annotation.annotation = "Test Step Annotation" annotation.user = user annotation.workflow_step = workflow_step_1 self.persist(annotation) assert workflow_step_1.id is not None h1 = model.History(name="WorkflowHistory1", user=user) invocation_uuid = uuid.uuid1() workflow_invocation = model.WorkflowInvocation() workflow_invocation.uuid = invocation_uuid workflow_invocation.history = h1 workflow_invocation_step1 = model.WorkflowInvocationStep() workflow_invocation_step1.workflow_invocation = workflow_invocation workflow_invocation_step1.workflow_step = workflow_step_1 subworkflow_invocation = model.WorkflowInvocation() workflow_invocation.attach_subworkflow_invocation_for_step(workflow_step_2, subworkflow_invocation) workflow_invocation_step2 = model.WorkflowInvocationStep() workflow_invocation_step2.workflow_invocation = workflow_invocation workflow_invocation_step2.workflow_step = workflow_step_2 workflow_invocation.workflow = workflow d1 = self.new_hda(h1, name="1") workflow_request_dataset = model.WorkflowRequestToInputDatasetAssociation() workflow_request_dataset.workflow_invocation = workflow_invocation workflow_request_dataset.workflow_step = workflow_step_1 workflow_request_dataset.dataset = d1 self.persist(workflow_invocation) assert workflow_request_dataset is not None assert workflow_invocation.id is not None history_id = h1.id self.expunge() loaded_invocation = self.query(model.WorkflowInvocation).get(workflow_invocation.id) assert loaded_invocation.uuid == invocation_uuid, "%s != %s" % (loaded_invocation.uuid, invocation_uuid) assert loaded_invocation assert loaded_invocation.history.id == history_id step_1, step_2 = loaded_invocation.workflow.steps assert not step_1.subworkflow assert step_2.subworkflow assert len(loaded_invocation.steps) == 2 subworkflow_invocation_assoc = loaded_invocation.get_subworkflow_invocation_association_for_step(step_2) assert subworkflow_invocation_assoc is not None assert isinstance(subworkflow_invocation_assoc.subworkflow_invocation, model.WorkflowInvocation) assert isinstance(subworkflow_invocation_assoc.parent_workflow_invocation, model.WorkflowInvocation) assert subworkflow_invocation_assoc.subworkflow_invocation.history.id == history_id loaded_workflow = self.query(model.Workflow).get(workflow_id) assert len(loaded_workflow.steps[0].annotations) == 1 copied_workflow = loaded_workflow.copy(user=user) annotations = copied_workflow.steps[0].annotations assert len(annotations) == 1
def invoke(self): workflow_invocation = self.workflow_invocation config = self.trans.app.config maximum_duration = getattr(config, "maximum_workflow_invocation_duration", -1) if maximum_duration > 0 and workflow_invocation.seconds_since_created > maximum_duration: log.debug( "Workflow invocation [%s] exceeded maximum number of seconds allowed for scheduling [%s], failing." % (workflow_invocation.id, maximum_duration)) workflow_invocation.state = model.WorkflowInvocation.states.FAILED # All jobs ran successfully, so we can save now self.trans.sa_session.add(workflow_invocation) # Not flushing in here, because web controller may create multiple # invocations. return self.progress.outputs if workflow_invocation.history.deleted: log.info("Cancelled workflow evaluation due to deleted history") raise modules.CancelWorkflowEvaluation() remaining_steps = self.progress.remaining_steps() delayed_steps = False for (step, workflow_invocation_step) in remaining_steps: step_delayed = False step_timer = ExecutionTimer() try: self.__check_implicitly_dependent_steps(step) if not workflow_invocation_step: workflow_invocation_step = model.WorkflowInvocationStep() workflow_invocation_step.workflow_invocation = workflow_invocation workflow_invocation_step.workflow_step = step workflow_invocation_step.state = 'new' workflow_invocation.steps.append(workflow_invocation_step) incomplete_or_none = self._invoke_step( workflow_invocation_step) if incomplete_or_none is False: step_delayed = delayed_steps = True workflow_invocation_step.state = 'ready' self.progress.mark_step_outputs_delayed( step, why="Not all jobs scheduled for state.") else: workflow_invocation_step.state = 'scheduled' except modules.DelayedWorkflowEvaluation as de: step_delayed = delayed_steps = True self.progress.mark_step_outputs_delayed(step, why=de.why) except Exception: log.exception( "Failed to schedule %s, problem occurred on %s.", self.workflow_invocation.workflow.log_str(), step.log_str(), ) raise if not step_delayed: log.debug("Workflow step %s of invocation %s invoked %s" % (step.id, workflow_invocation.id, step_timer)) if delayed_steps: state = model.WorkflowInvocation.states.READY else: state = model.WorkflowInvocation.states.SCHEDULED workflow_invocation.state = state # All jobs ran successfully, so we can save now self.trans.sa_session.add(workflow_invocation) # Not flushing in here, because web controller may create multiple # invocations. return self.progress.outputs