def _check(self, name, check_compiled, check_storage_ensured): """Check (and raise) if the engine has not reached a certain stage.""" if check_compiled and not self._compiled: raise exc.InvalidState("Can not %s an engine which" " has not been compiled" % name) if check_storage_ensured and not self._storage_ensured: raise exc.InvalidState("Can not %s an engine" " which has not has its storage" " populated" % name)
def wrapper(self, *args, **kwargs): if check_compiled and not self._compiled: raise exc.InvalidState("Can not %s an engine which" " has not been compiled" % do_what) if check_storage_ensured and not self._storage_ensured: raise exc.InvalidState("Can not %s an engine" " which has not had its storage" " populated" % do_what) if check_validated and not self._validated: raise exc.InvalidState("Can not %s an engine which" " has not been validated" % do_what) return meth(self, *args, **kwargs)
def process_event(self, event): """Trigger a state change in response to the provided event. :param event: event to be processed to cause a potential transition """ current = self._current if current is None: raise NotInitialized("Can only process events after" " being initialized (not before)") if self._states[current.name]['terminal']: raise excp.InvalidState("Can not transition from terminal" " state '%s' on event '%s'" % (current.name, event)) if event not in self._transitions[current.name]: raise excp.NotFound("Can not transition from state '%s' on" " event '%s' (no defined transition)" % (current.name, event)) replacement = self._transitions[current.name][event] if current.on_exit is not None: current.on_exit(current.name, event) if replacement.on_enter is not None: replacement.on_enter(replacement.name, event) self._current = replacement return ( self._states[replacement.name]['reactions'].get(event), self._states[replacement.name]['terminal'], )
def initialize(self): """Sets up the state machine (sets current state to start state...).""" if self._start_state not in self._states: raise excp.NotFound("Can not start from a undefined" " state '%s'" % (self._start_state)) if self._states[self._start_state]['terminal']: raise excp.InvalidState("Can not start from a terminal" " state '%s'" % (self._start_state)) self._current = _Jump(self._start_state, None, None)
def check_job_transition(old_state, new_state): """Check that job can transition from from ``old_state`` to ``new_state``. If transition can be performed, it returns true. If transition should be ignored, it returns false. If transition is not valid, it raises an InvalidState exception. """ if old_state == new_state: return False pair = (old_state, new_state) if pair in _ALLOWED_JOB_TRANSITIONS: return True raise exc.InvalidState("Job transition from '%s' to '%s' is not allowed" % pair)
def initialize(self): """Sets up the state machine (sets current state to start state...).""" if self._start_state not in self._states: raise excp.NotFound("Can not start from a undefined" " state '%s'" % (self._start_state)) if self._states[self._start_state]['terminal']: raise excp.InvalidState("Can not start from a terminal" " state '%s'" % (self._start_state)) # No on enter will be called, since we are priming the state machine # and have not really transitioned from anything to get here, we will # though allow 'on_exit' to be called on the event that causes this # to be moved from... self._current = _Jump(self._start_state, None, self._states[self._start_state]['on_exit'])
def check_flow_transition(old_state, new_state): """Check that flow can transition from old_state to new_state. If transition can be performed, it returns True. If transition should be ignored, it returns False. If transition is not valid, it raises InvalidState exception. """ if old_state == new_state: return False pair = (old_state, new_state) if pair in _ALLOWED_FLOW_TRANSITIONS: return True if pair in _IGNORED_FLOW_TRANSITIONS: return False raise exc.InvalidState("Flow transition from %s to %s is not allowed" % pair)
def prepare(self): if not self._compiled: raise exc.InvalidState("Can not prepare an engine" " which has not been compiled") if not self._storage_ensured: # Set our own state to resuming -> (ensure atoms exist # in storage) -> suspended in the storage unit and notify any # attached listeners of these changes. self._change_state(states.RESUMING) self._ensure_storage() self._change_state(states.SUSPENDED) self._storage_ensured = True # Reset everything back to pending (if we were previously reverted). if self.storage.get_flow_state() == states.REVERTED: self._runtime.reset_all() self._change_state(states.PENDING)
def check_task_transition(old_state, new_state): """Check that task can transition from old_state to new_state. If transition can be performed, it returns True. If transition should be ignored, it returns False. If transition is not valid, it raises InvalidState exception. """ pair = (old_state, new_state) if pair in _ALLOWED_TASK_TRANSITIONS: return True if pair in _IGNORED_TASK_TRANSITIONS: return False # TODO(harlowja): Should we check/allow for 3rd party states to be # triggered during RUNNING by having a concept of a sub-state that we also # verify against?? raise exc.InvalidState("Task transition from %s to %s is not allowed" % pair)
def prepare(self): if not self._compiled: raise exc.InvalidState("Can not prepare an engine" " which has not been compiled") if not self._storage_ensured: self._ensure_storage() self._storage_ensured = True # At this point we can check to ensure all dependencies are either # flow/task provided or storage provided, if there are still missing # dependencies then this flow will fail at runtime (which we can avoid # by failing at preparation time). external_provides = set(self.storage.fetch_all().keys()) missing = self._flow.requires - external_provides if missing: raise exc.MissingDependencies(self._flow, sorted(missing)) # Reset everything back to pending (if we were previously reverted). if self.storage.get_flow_state() == states.REVERTED: self._runtime.reset_all() self._change_state(states.PENDING)
def transition(self, new_state): """Transitions the request to a new state. If transition was performed, it returns True. If transition should was ignored, it returns False. If transition was not valid (and will not be performed), it raises an InvalidState exception. """ old_state = self._state if old_state == new_state: return False pair = (old_state, new_state) if pair not in _ALLOWED_TRANSITIONS: raise excp.InvalidState("Request transition from %s to %s is" " not allowed" % pair) if new_state in _STOP_TIMER_STATES: self._watch.stop() self._state = new_state LOG.debug("Transitioned '%s' from %s state to %s state", self, old_state, new_state) return True
def transition(self, new_state): """Transitions the request to a new state. If transition was performed, it returns True. If transition was ignored, it returns False. If transition was not valid (and will not be performed), it raises an InvalidState exception. """ old_state = self._machine.current_state if old_state == new_state: return False try: self._machine.process_event(make_an_event(new_state)) except (machine_excp.NotFound, machine_excp.InvalidState) as e: raise excp.InvalidState("Request transition from %s to %s is" " not allowed: %s" % (old_state, new_state, e)) else: if new_state in STOP_TIMER_STATES: self._watch.stop() LOG.debug("Transitioned '%s' from %s state to %s state", self, old_state, new_state) return True
def validate(self): if not self._storage_ensured: raise exc.InvalidState("Can not validate an engine" " which has not has its storage" " populated") # At this point we can check to ensure all dependencies are either # flow/task provided or storage provided, if there are still missing # dependencies then this flow will fail at runtime (which we can avoid # by failing at validation time). execution_graph = self._compilation.execution_graph if LOG.isEnabledFor(logging.BLATHER): LOG.blather( "Validating scoping and argument visibility for" " execution graph with %s nodes and %s edges with" " density %0.3f", execution_graph.number_of_nodes(), execution_graph.number_of_edges(), nx.density(execution_graph)) missing = set() fetch = self.storage.fetch_unsatisfied_args for node in execution_graph.nodes_iter(): missing.update( fetch(node.name, node.rebind, optional_args=node.optional)) if missing: raise exc.MissingDependencies(self._flow, sorted(missing))
def suspend(self): if not self._compiled: raise exc.InvalidState("Can not suspend an engine" " which has not been compiled") self._change_state(states.SUSPENDING)