Extensions to the transaction package.
nti.transactions.loop.TransactionsLoop is a retryable
transaction manager. It is conceptually similar to the attempts
context manager provided by the transaction package itself, but much
more powerful and extensible via subclasses. Features include:
Configurable commit vetos.
Extensible tests for which exceptions should be retried.
The ability to abort the transaction and bypass a potentially expensive commit when there are expected to be no side-effects.
Sleeping between retries.
Extensive logging and timing.
The TransactionLoop can be used as-is, or it can be subclassed for
customization. For use in a Pyramid tween, for example, a minimal
subclass might look like this (see
for a full-featured tween):
>>> class PyramidTransactionLoop(TransactionLoop): ... def prep_for_retry(self, number, request): ... request.make_body_seekable() ... def describe_transaction(self, request): ... return request.url
A few data managers are provided for convenience.
The first data manager is used to put an object in a
(something with the
put_nowait methods) when a
transaction succeeds. If the queue is full, then the transaction will
not be allowed to commit:
>>> from nti.transactions.queue import put_nowait >>> put_nowait(queue, object)
This is a special case of the
ObjectDataManager, which will call
one method with any arguments when a transaction commits. It can be
configured to vote on whether the transaction should be allowed to commit.
or not. This is useful for, say, putting an item in a Redis queue when
the transaction is successful. It can be constructed directly, but the
do function is a shorthand way of joining one to the current
>>> from nti.transactions.manager import do >>> do(print, args=("Committed"))
See the documentation of this object for numerous warnings about side-effects and its interaction with the transaction machinery. Use it with care!
Interfaces for nti.transactions.
Aborting the active transaction failed for an unknown and unexpected reason.
This is raised instead of raising very generic system exceptions such as ValueError and AttributeError.
Committing the active transaction failed for an unknown and unexpected reason.
This is raised instead of raising very generic system exceptions such as TypeError.
Raised when a transaction manager has its transaction changed while a controlling transaction loop believes it is in control.
The handler first aborted or committed the transaction, and then began a new one. Possibly many times.
A kind of
TransactionLifecycleError. Applications must not raise this exception.
This is a programming error.
A new transaction has begun.
Extensions to the transaction api.
Description of why a loop was invoked.
The handler to run.
The loop doing the running.
The arguments passed to the handler
The keyword arguments passed to the handler.
Base class for attempt events.
The number of the attempt. Starts at 0.
The first attempt.
A retry attempt.
Will sleep between attempts.
sleep_timeattribute is modified, that will be the time slept.
The time to sleep.
Raised when an application commits or aborts a transaction while the transaction controller believes it is in control.
Applications must not raise this exception.
This may have happened many times; we cannot detect that.
This is a programming error.
Support for data managers.
ObjectDataManager(target=None, method_name=None, call=None, vote=None, args=(), kwargs=None)¶
A generic (and therefore relatively expensive)
transaction.interfaces.IDataManagerthat invokes a callable (usually a method of an object) when the transaction finishes successfully. The method should not raise exceptions when invoked, as they will be caught and ignored (to preserve consistency with the rest of the data managers). If there’s a chance the method could fail, then whatever actions it does take should not have side-effects.
These data managers have no guaranteed relationship to other data managers in terms of the order of which they commit, except as documented with
Because these data managers execute exactly one operation on a complete transaction commit, implementing a savepoint is trivial: do nothing when it is rolled back. A savepoint is created to checkpoint a transaction and rolled back to reverse actions taken after the checkpoint. Only data managers that were active (joined) at the time the transaction savepoint is created are asked to create their own savepoint, and then potentially to roll it back. We do no work until the transaction is committed, so we have nothing to rollback. Moroever, if a transaction savepoint is activated before a manager joins, then that manager is not asked for its own savepoint: it is simply aborted and unjoined from the transaction if the previous savepoint is rolledback.
Return the string value that, when sorted, determines the order in which data managers will get to vote and commit at the end of a transaction. (See
The default implementation of this method uses the ID of either the
targetobject we were initialized with or the ID of the actual callable we will call. This has the property of ensuring that all calls to methods of a particular object instance (when
targetis given), or calls to a particular callable (when
targetis not given) will execute in the order in which they were added to the transaction.
This relies on an implementation detail of the transaction package, which sorts using
list.sort(), which is guaranteed to be stable: thus objects using the same key remain in the same relative order. (See
To execute only calls to a particular method of a particular instance in the order they are added to the transaction, but allow other methods to execute before or after them, do not provide the
It is not advisable to use the ID of this object (
self) in the implementation of this method, because the ID values are not guaranteed to be monotonically increasing and thus instances of a particular class that did this would execute in “random” order.
OrderedNearEndObjectDataManager(target=None, method_name=None, call=None, vote=None, args=(), kwargs=None)¶
A special extension of
ObjectDataManagerthat attempts to execute after all other data managers have executed. This is useful when an operation relies on the execution of other data managers.
New in version 1.1.
Sort prepended with z’s in an attempt to execute after other data managers.
Establishes a IDataManager in the current transaction. See
ObjectDataManagerfor the possible arguments.
Support for transactionally working with queues.