Errors

Exceptions

edzed defines these exceptions:

exception edzed.EdzedError

Base class for exceptions listed below.

exception edzed.EdzedCircuitError

Raised for any error related to the circuit and its blocks where a standard exception like ValueError or TypeError is not fully appropriate.

exception edzed.EdzedInvalidState

This exception is raised for calls that were made in a wrong situation, e.g. when trying to start a simulation when it is already running or when attempting an operation on an uninitialized block.

exception edzed.EdzedUnknownEvent

This specific exception is raised when SBlock.event() is called with an event type that the block does not recognize.

Error checking in asyncio

A non-trivial asyncio application may need several long-running tasks. Even if the code was written in agreement with the “Errors should never pass silently” guideline, tasks in asyncio are “fire and forget”. When a task crashes, the rest of the program continues to run. The application could become unresponsive or ill-behaving.

Important

Make sure an unexpected asyncio task termination cannot happen unnoticed.

There are several options (and combinations):

  • use wrappers around the task coroutines. When the code after a try / await task_coro() / except block is reached, you know that the task coroutine has terminated. edzed follows this approach in some of its async sequential blocks using a helper AddonAsync._create_monitored_task().

  • do not treat any task as a “background task”. Organize your application in a way that spawning of new tasks and their awaiting forms a single code block. The run() function is based on this principle.

  • customize the global event loop’s error handler, see loop.set_exception_handler() in asyncio.

And, of course, check the results of terminated tasks.

Reporting errors to the simulator

When a fatal error occurs in an edzed related function, the simulation can be aborted with the Circuit.abort() method.

In most cases it is sufficient to simply raise an exception as usual, because the simulator will receive the exception. In reaction it will abort the simulation unless the error is deliberately ignored. All such cases are properly documented.

However - as explained in the previous section - exceptions raised in asynchronous tasks affect only the task itself. If a simulation abort is desired by an independent task, Circuit.abort() must be called explicitly.

Circuit.abort(exc: Exception) None

Abort the circuit simulation due to an exception.

abort() is necessary only when an exception wouldn’t be propagated to the simulator. This is the case in asyncio tasks neither started with the AddonAsync._create_monitored_task() helper, nor started as supporting tasks in run().

The first error stops the simulation, that’s why abort() delivers the exception only if the simulation hasn’t received another exception already.

abort() may be called even before the simulation begins. The start will then fail.

Detection of erroneous circuit activity

The simulator aborts the simulation when it detects erroneous activity described below. Both cases are similar, one is related to outputs and one to events.

  • Instability

    A circuit instability occurs when the circuit is unable to settle down. It happens when a change in an output value triggers output change in the directly connected blocks and then in the indirectly connected blocks and so on. When the change propagates through the whole circuit several times, the circuit is deemed unstable.

  • Recursive events

    A sequential block handling an event can send one or more events to other blocks. The recipient blocks may respond by generating events too. This is allowed unless there is a loop resulting in an event being sent to the block which is not ready to handle it, because it did not finish the handling of the current event.

    Important

    While a block is handling an event, it will raise an exception when it receives an event.

    Because event delivery is synchronous, the only possible cause for this exception is the forbidden loop described above.

    Exception from the rule: An FSM may send one event to itself under specific circumstances described in chained state transitions.