Total Complexity | 10 |
Total Lines | 55 |
Duplicated Lines | 0 % |
Changes | 0 |
1 | # -*- coding: utf-8 -*- |
||
2 | |||
3 | from functools import wraps |
||
4 | |||
5 | import transaction |
||
6 | from bika.lims import api |
||
7 | from senaite.core import logger |
||
8 | from ZODB.POSException import ConflictError |
||
9 | |||
10 | |||
11 | def readonly_transaction(func): |
||
12 | """Decorator to doom the current transaction |
||
13 | |||
14 | https://transaction.readthedocs.io/en/latest/doom.html#dooming-transactions |
||
15 | """ |
||
16 | @wraps(func) |
||
17 | def decorator(self, *args, **kwargs): |
||
18 | logger.info("*** READONLY TRANSACTION: '{}.{}' ***". |
||
19 | format(self.__class__.__name__, self.__name__)) |
||
20 | tx = transaction.get() |
||
21 | tx.doom() |
||
22 | return func(self, *args, **kwargs) |
||
23 | return decorator |
||
24 | |||
25 | |||
26 | def retriable(count=3, sync=False, reraise=True, on_retry_exhausted=None): |
||
27 | """Retries DB commits |
||
28 | """ |
||
29 | |||
30 | def decorator(func): |
||
31 | def wrapped(*args, **kwargs): |
||
32 | retried = 0 |
||
33 | if sync: |
||
34 | try: |
||
35 | api.get_portal()._p_jar.sync() |
||
36 | except Exception: |
||
37 | pass |
||
38 | while retried < count: |
||
39 | try: |
||
40 | return func(*args, **kwargs) |
||
41 | except ConflictError: |
||
42 | retried += 1 |
||
43 | logger.warn("DB ConflictError: Retrying %s/%s" |
||
44 | % (retried, count)) |
||
45 | try: |
||
46 | api.get_portal()._p_jar.sync() |
||
47 | except Exception: |
||
48 | if retried >= count: |
||
49 | if on_retry_exhausted is not None: |
||
50 | on_retry_exhausted(*args, **kwargs) |
||
51 | if reraise: |
||
52 | raise |
||
53 | return wrapped |
||
54 | return decorator |
||
55 |