Execute the given action.

    An action is any object with a ``forwards()`` and ``backwards()`` method.

    .. code-block:: python

        class CreateUser(object):

            def __init__(self, userinfo):
                self.userinfo = userinfo
                self.user_id  = None

            def forwards(self):
                self.user_id = UserStore.create(userinfo)
                return self.user_id

            def backwards(self):
                if self.user_id is not None:
                    # user_id will be None if creation failed
                    UserStore.delete(self.user_id)

    If the ``forwards`` method succeeds, the action is considered successful.
    If the method fails, the ``backwards`` method is called to revert any
    effect it might have had on the system.

    In addition to defining classes, actions may be built using the
    :py:func:`reversible.action` decorator. Actions may be composed together
    using the :py:func:`reversible.gen` decorator.

    :param action:
        The action to execute.
    :returns:
        The value returned by the ``forwards()`` method of the action.
    :raises:
        The exception raised by the ``forwards()`` method if rollback
        succeeded. Otherwise, the exception raised by the ``backwards()``
        method is raised.

def execute(action):
    """
    Execute the given action.

    An action is any object with a ``forwards()`` and ``backwards()`` method.

    .. code-block:: python

        class CreateUser(object):

            def __init__(self, userinfo):
                self.userinfo = userinfo
                self.user_id  = None

            def forwards(self):
                self.user_id = UserStore.create(userinfo)
                return self.user_id

            def backwards(self):
                if self.user_id is not None:
                    # user_id will be None if creation failed
                    UserStore.delete(self.user_id)

    If the ``forwards`` method succeeds, the action is considered successful.
    If the method fails, the ``backwards`` method is called to revert any
    effect it might have had on the system.

    In addition to defining classes, actions may be built using the
    :py:func:`reversible.action` decorator. Actions may be composed together
    using the :py:func:`reversible.gen` decorator.

    :param action:
        The action to execute.
    :returns:
        The value returned by the ``forwards()`` method of the action.
    :raises:
        The exception raised by the ``forwards()`` method if rollback
        succeeded. Otherwise, the exception raised by the ``backwards()``
        method is raised.
    """
    # TODO this should probably be a class to configure logging, etc. The
    # global execute can refer to the "default" instance of the executor.
    try:
        return action.forwards()
    except Exception:
        log.exception('%s failed to execute. Rolling back.', action)
        try:
            action.backwards()
        except Exception:
            log.exception('%s failed to roll back.', action)
            raise
        else:
            raise