Closed thedrow closed 3 years ago
Hi @thedrow,
the current way to do this is using finalize_event
callbacks to check for errors. Alternatively, you could extend your own Event
for some convenience:
from transitions import Machine, Event
class ErrorEvent(Event):
def _process(self, event_data):
try:
return super()._process(event_data)
except Exception:
event_data.args = [event_data.error]
event_data.machine.callbacks(["on_exception"], event_data)
class ErrorMachine(Machine):
event_cls = ErrorEvent
def on_exception(self, error):
print("Help:", error)
def raise_exception(self):
raise Exception("Oh noes!")
m = ErrorMachine(after_state_change='raise_exception')
m.to_initial()
Having on_exception
in core
would be useful but I fear that this could become quite complex to handle (should ALL exceptions be caught? should exceptions be raised? only when there is no on_exception
attached to a model?). Let's see if there is some feedback considering this.
I personally think there's room in the core for this sort of functionality.
should ALL exceptions be caught?
Need to think this through, but my initial thought is yes. I'd leave the handling up to the user.
should exceptions be raised? only when there is no on_exception attached to a model?
Yes, that seems reasonable. Raise normally unless the callback is registered.
I need same functionality now(but for AsyncMachine), to not wrap code inside each transition into try except block
it will be very useful to have on_exception
callback where I can catch all errors inside async callbacks
I opted for a simpler less invasive version for on_exception
(than ignore_invalid_callbacks
) and pushed it to master
closing this since there has been no report of issues or improvement suggestions. If you experience issues with on_exception
, please open a bug report.
Can you please showcase an example of using the on_exception
callback to change the state of the model to a desired fail state?
On doing a transition like self.to_failure()
in the exception callback , it essentially results in a infinite loop.
On doing a transition like self.to_failure() in the exception callback , it essentially results in a infinite loop.
Hello @e0lithic, please open a separate issue or a discussion instead of commenting on a two years old closed issue. There is no specific magic involved in handling exceptions:
from transitions import Machine
class Model:
def handle_error(self):
self.to_failed()
def on_enter_failing(self):
raise RuntimeError("Failing!")
model = Model()
machine = Machine(model=model, states=['initial', 'failing', 'failed'], initial='initial',
on_exception='handle_error')
assert model.is_initial()
model.to_failing()
assert model.is_failed()
You should make sure that a failure recovering procedure does not raise exceptions itself. If you end up in an infinite loop, it is very likely that your to_failure
trigger raises an exception though.
It'd be useful to be able to handle exceptions raised inside callbacks using
on_exception
callbacks.In my case, I want to transition to the
crashed
state whenever an unhandled exception is raised during transitions.