diff options
| author | Joshua Harlow <harlowja@yahoo-inc.com> | 2015-11-16 16:27:42 -0800 |
|---|---|---|
| committer | Joshua Harlow <harlowja@gmail.com> | 2016-01-09 22:42:17 -0800 |
| commit | 8e8156c488dea8ae876b112c30e41e60da4f5be7 (patch) | |
| tree | a4c119dda7d2338bd8c63aad593bbb42d24f3e1f /taskflow/engines/action_engine/engine.py | |
| parent | f555a35f3081ba492db15d7bda11fbe50f2a8349 (diff) | |
| download | taskflow-8e8156c488dea8ae876b112c30e41e60da4f5be7.tar.gz | |
Allow for alterations in decider 'area of influence'
Christmas came early.
Closes-Bug: #1479466
Change-Id: I931d826690c925f022dbfffe9afb7bf41345b1d0
Diffstat (limited to 'taskflow/engines/action_engine/engine.py')
| -rw-r--r-- | taskflow/engines/action_engine/engine.py | 104 |
1 files changed, 62 insertions, 42 deletions
diff --git a/taskflow/engines/action_engine/engine.py b/taskflow/engines/action_engine/engine.py index c65da34..7084f51 100644 --- a/taskflow/engines/action_engine/engine.py +++ b/taskflow/engines/action_engine/engine.py @@ -99,37 +99,37 @@ class ActionEngine(base.Engine): **Engine options:** - +-------------------+-----------------------+------+-----------+ - | Name/key | Description | Type | Default | - +===================+=======================+======+===========+ - | defer_reverts | This option lets you | bool | ``False`` | - | | safely nest flows | | | - | | with retries inside | | | - | | flows without retries | | | - | | and it still behaves | | | - | | as a user would | | | - | | expect (for example | | | - | | if the retry gets | | | - | | exhausted it reverts | | | - | | the outer flow unless | | | - | | the outer flow has a | | | - | | has a separate retry | | | - | | behavior). | | | - +-------------------+-----------------------+------+-----------+ - | inject_transient | When true, values | bool | ``True`` | - | | that are local to | | | - | | each atoms scope | | | - | | are injected into | | | - | | storage into a | | | - | | transient location | | | - | | (typically a local | | | - | | dictionary), when | | | - | | false those values | | | - | | are instead persisted | | | - | | into atom details | | | - | | (and saved in a non- | | | - | | transient manner). | | | - +-------------------+-----------------------+------+-----------+ + +----------------------+-----------------------+------+------------+ + | Name/key | Description | Type | Default | + +======================+=======================+======+============+ + | ``defer_reverts`` | This option lets you | bool | ``False`` | + | | safely nest flows | | | + | | with retries inside | | | + | | flows without retries | | | + | | and it still behaves | | | + | | as a user would | | | + | | expect (for example | | | + | | if the retry gets | | | + | | exhausted it reverts | | | + | | the outer flow unless | | | + | | the outer flow has a | | | + | | has a separate retry | | | + | | behavior). | | | + +----------------------+-----------------------+------+------------+ + | ``inject_transient`` | When true, values | bool | ``True`` | + | | that are local to | | | + | | each atoms scope | | | + | | are injected into | | | + | | storage into a | | | + | | transient location | | | + | | (typically a local | | | + | | dictionary), when | | | + | | false those values | | | + | | are instead persisted | | | + | | into atom details | | | + | | (and saved in a non- | | | + | | transient manner). | | | + +----------------------+-----------------------+------+------------+ """ NO_RERAISING_STATES = frozenset([states.SUSPENDED, states.SUCCESS]) @@ -148,6 +148,12 @@ class ActionEngine(base.Engine): end-users when doing execution iterations via :py:meth:`.run_iter`. """ + MAX_MACHINE_STATES_RETAINED = 10 + """ + During :py:meth:`~.run_iter` the last X state machine transitions will + be recorded (typically only useful on failure). + """ + def __init__(self, flow, flow_detail, backend, options): super(ActionEngine, self).__init__(flow, flow_detail, backend, options) self._runtime = None @@ -242,16 +248,21 @@ class ActionEngine(base.Engine): self.compile() self.prepare() self.validate() - last_state = None + # Keep track of the last X state changes, which if a failure happens + # are quite useful to log (and the performance of tracking this + # should be negligible). + last_transitions = collections.deque( + maxlen=max(1, self.MAX_MACHINE_STATES_RETAINED)) with _start_stop(self._task_executor, self._retry_executor): self._change_state(states.RUNNING) try: closed = False machine, memory = self._runtime.builder.build(timeout=timeout) r = runners.FiniteRunner(machine) - for (_prior_state, new_state) in r.run_iter(builder.START): - last_state = new_state - # NOTE(harlowja): skip over meta-states. + for transition in r.run_iter(builder.START): + last_transitions.append(transition) + _prior_state, new_state = transition + # NOTE(harlowja): skip over meta-states if new_state in builder.META_STATES: continue if new_state == states.FAILURE: @@ -271,15 +282,24 @@ class ActionEngine(base.Engine): self.suspend() except Exception: with excutils.save_and_reraise_exception(): + LOG.exception("Engine execution has failed, something" + " bad must of happened (last" + " %s machine transitions were %s)", + last_transitions.maxlen, + list(last_transitions)) self._change_state(states.FAILURE) else: - if last_state and last_state not in self.IGNORABLE_STATES: - self._change_state(new_state) - if last_state not in self.NO_RERAISING_STATES: - it = itertools.chain( - six.itervalues(self.storage.get_failures()), - six.itervalues(self.storage.get_revert_failures())) - failure.Failure.reraise_if_any(it) + if last_transitions: + _prior_state, new_state = last_transitions[-1] + if new_state not in self.IGNORABLE_STATES: + self._change_state(new_state) + if new_state not in self.NO_RERAISING_STATES: + failures = self.storage.get_failures() + more_failures = self.storage.get_revert_failures() + fails = itertools.chain( + six.itervalues(failures), + six.itervalues(more_failures)) + failure.Failure.reraise_if_any(fails) @staticmethod def _check_compilation(compilation): |
