Transaction convenience support¶
- (We really need to write proper documentation for the transaction
- package, but I don’t want to block the conveniences documented here for that.)
We can now use the with statement to define transaction boundaries.
>>> import transaction.tests.savepointsample >>> dm = transaction.tests.savepointsample.SampleSavepointDataManager() >>> list(dm.keys()) 
We can use it with a manager:
>>> with transaction.manager as t: ... dm['z'] = 3 ... t.note(u'test 3') >>> dm['z'] 3 >>> dm.last_note == u'test 3' True >>> with transaction.manager: #doctest ELLIPSIS ... dm['z'] = 4 ... xxx Traceback (most recent call last): ... NameError: ... name 'xxx' is not defined >>> dm['z'] 3
On Python 2, you can also abbreviate
with transaction.manager: as
transaction:. This does not work on Python 3 (see see
Commits can fail for transient reasons, especially conflicts. Applications will often retry transactions some number of times to overcome transient failures. This typically looks something like:
for i in range(3): try: with transaction.manager: ... some something ... except SomeTransientException: continue else: break
This is rather ugly and easy to get wrong.
Transaction managers provide two helpers for this case.
Running and retrying functions as transactions¶
The first helper runs a function as a transaction:
def do_somthing(): "Do something" ... some something ... transaction.manager.run(do_somthing)
You can also use this as a decorator, which executes the decorated function immediately :
@transaction.manager.run def _(): "Do something" ... some something ...
The transaction manager
run method will run the function and
return the results. If the function raises a
function will be retried a configurable number of times, 3 by
default. Any other exceptions will be raised.
The function name (if it isn’t
'_') and docstring, if any, are
added to the transaction description.
You can pass an integer number of times to try to the
transaction.manager.run(do_somthing, 9) @transaction.manager.run(9) def _(): "Do something" ... some something ...
The default number of times to try is 3.
Retrying code blocks using a attempt iterator¶
An older helper for running transactions uses an iterator of attempts:
for attempt in transaction.manager.attempts(): with attempt as t: ... some something ...
This runs the code block until it runs without a transient error or until the number of attempts is exceeded. By default, it tries 3 times, but you can pass a number of attempts:
for attempt in transaction.manager.attempts(9): with attempt as t: ... some something ...
|||Some people find this easier to read, even
though the result isn’t a decorated function, but rather the result of
calling it in a transaction. The function name |