Rework due to code comments.
This commit is contained in:
		@@ -27,6 +27,7 @@ from taskflow import exceptions as exc
 | 
			
		||||
from taskflow import job
 | 
			
		||||
from taskflow import jobboard
 | 
			
		||||
from taskflow import logbook
 | 
			
		||||
from taskflow import states
 | 
			
		||||
from taskflow import utils
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
@@ -165,6 +166,9 @@ class MemoryJobBoard(jobboard.JobBoard):
 | 
			
		||||
                    break
 | 
			
		||||
            if not exists:
 | 
			
		||||
                raise exc.JobNotFound()
 | 
			
		||||
            if j.state not in (states.SUCCESS, states.FAILURE):
 | 
			
		||||
                raise exc.InvalidStateException("Can not delete a job in "
 | 
			
		||||
                                                "state %s" % (j.state))
 | 
			
		||||
            self._board = [(d, j) for (d, j) in self._board if j != job]
 | 
			
		||||
 | 
			
		||||
    @check_not_closed
 | 
			
		||||
 
 | 
			
		||||
@@ -77,21 +77,50 @@ class Workflow(object):
 | 
			
		||||
        else:
 | 
			
		||||
            result_fetcher = None
 | 
			
		||||
 | 
			
		||||
        self.state = states.STARTED
 | 
			
		||||
        for task in self.tasks:
 | 
			
		||||
        self._change_state(context, states.STARTED)
 | 
			
		||||
 | 
			
		||||
        # TODO(harlowja): we can likely add in custom reconcilation strategies
 | 
			
		||||
        # here or around here...
 | 
			
		||||
        def do_rollback_for(task, ex):
 | 
			
		||||
            self._change_state(context, states.REVERTING)
 | 
			
		||||
            with excutils.save_and_reraise_exception():
 | 
			
		||||
                try:
 | 
			
		||||
                    self._on_task_error(context, task)
 | 
			
		||||
                except Exception:
 | 
			
		||||
                    LOG.exception("Dropping exception catched when"
 | 
			
		||||
                                  " notifying about existing task"
 | 
			
		||||
                                  " exception.")
 | 
			
		||||
                self.rollback(context, exc.TaskException(task, self, ex))
 | 
			
		||||
                self._change_state(context, states.FAILURE)
 | 
			
		||||
 | 
			
		||||
        self._change_state(context, states.RESUMING)
 | 
			
		||||
        last_task = 0
 | 
			
		||||
        if result_fetcher:
 | 
			
		||||
            for (i, task) in enumerate(self.tasks):
 | 
			
		||||
                (has_result, result) = result_fetcher(context, self, task)
 | 
			
		||||
                if not has_result:
 | 
			
		||||
                    break
 | 
			
		||||
                # Fake running the task so that we trigger the same
 | 
			
		||||
                # notifications and state changes (and rollback that would
 | 
			
		||||
                # have happened in a normal flow).
 | 
			
		||||
                last_task = i + 1
 | 
			
		||||
                try:
 | 
			
		||||
                    self._on_task_start(context, task)
 | 
			
		||||
                    # Keep a pristine copy of the result
 | 
			
		||||
                    # so that if said result is altered by other further
 | 
			
		||||
                    # states the one here will not be. This ensures that
 | 
			
		||||
                    # if rollback occurs that the task gets exactly the
 | 
			
		||||
                    # result it returned and not a modified one.
 | 
			
		||||
                    self.results.append((task, copy.deepcopy(result)))
 | 
			
		||||
                    self._on_task_finish(context, task, result)
 | 
			
		||||
                except Exception as ex:
 | 
			
		||||
                    do_rollback_for(task, ex)
 | 
			
		||||
 | 
			
		||||
        self._change_state(context, states.RUNNING)
 | 
			
		||||
        for task in self.tasks[last_task:]:
 | 
			
		||||
            try:
 | 
			
		||||
                # See if we have already ran this.
 | 
			
		||||
                result = None
 | 
			
		||||
                has_result = False
 | 
			
		||||
                if result_fetcher:
 | 
			
		||||
                    (has_result, result) = result_fetcher(context, self, task)
 | 
			
		||||
                if not has_result:
 | 
			
		||||
                    self.state = state.RUNNING
 | 
			
		||||
                else:
 | 
			
		||||
                    self.state = state.RESUMING
 | 
			
		||||
                self._on_task_start(context, task)
 | 
			
		||||
                if not has_result:
 | 
			
		||||
                    result = task.apply(context, *args, **kwargs)
 | 
			
		||||
                result = task.apply(context, *args, **kwargs)
 | 
			
		||||
                # Keep a pristine copy of the result
 | 
			
		||||
                # so that if said result is altered by other further states
 | 
			
		||||
                # the one here will not be. This ensures that if rollback
 | 
			
		||||
@@ -100,19 +129,20 @@ class Workflow(object):
 | 
			
		||||
                self.results.append((task, copy.deepcopy(result)))
 | 
			
		||||
                self._on_task_finish(context, task, result)
 | 
			
		||||
            except Exception as ex:
 | 
			
		||||
                self.state = states.FAILURE
 | 
			
		||||
                with excutils.save_and_reraise_exception():
 | 
			
		||||
                    try:
 | 
			
		||||
                        self._on_task_error(context, task)
 | 
			
		||||
                    except Exception:
 | 
			
		||||
                        LOG.exception("Dropping exception catched when"
 | 
			
		||||
                                      " notifying about existing task"
 | 
			
		||||
                                      " exception.")
 | 
			
		||||
                    self.state = states.REVERTING
 | 
			
		||||
                    self.rollback(context, exc.TaskException(task, self, ex))
 | 
			
		||||
                    self.state = states.FAILURE
 | 
			
		||||
                do_rollback_for(task, ex)
 | 
			
		||||
 | 
			
		||||
        # Only gets here if everything went successfully.
 | 
			
		||||
        self.state = states.SUCCESS
 | 
			
		||||
        self._change_state(context, states.SUCCESS)
 | 
			
		||||
 | 
			
		||||
    def _change_state(self, context, new_state):
 | 
			
		||||
        if self.state != new_state:
 | 
			
		||||
            self.state = new_state
 | 
			
		||||
            self._on_flow_state_change(context)
 | 
			
		||||
 | 
			
		||||
    def _on_flow_state_change(self, context):
 | 
			
		||||
        # Notify any listeners that the internal state has changed.
 | 
			
		||||
        for i in self.listeners:
 | 
			
		||||
            i.notify(context, self)
 | 
			
		||||
 | 
			
		||||
    def _on_task_error(self, context, task):
 | 
			
		||||
        # Notify any listeners that the task has errored.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user