Merge lp:~allenap/maas/transactional-close-connections-on-outermost-exit-only into lp:~maas-committers/maas/trunk

Proposed by Gavin Panella
Status: Merged
Approved by: Graham Binns
Approved revision: no longer in the source branch.
Merged at revision: 2941
Proposed branch: lp:~allenap/maas/transactional-close-connections-on-outermost-exit-only
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 55 lines (+23/-2)
2 files modified
src/maasserver/utils/async.py (+4/-1)
src/maasserver/utils/tests/test_async.py (+19/-1)
To merge this branch: bzr merge lp:~allenap/maas/transactional-close-connections-on-outermost-exit-only
Reviewer Review Type Date Requested Status
Graham Binns (community) Approve
Review via email: mp+234092@code.launchpad.net

Commit message

When using the transactional decorator, only close old connections when leaving the outermost atomic block.

Previously it would close connections at all levels, causing transactions to be silently aborted.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/utils/async.py'
2--- src/maasserver/utils/async.py 2014-08-13 21:49:35 +0000
3+++ src/maasserver/utils/async.py 2014-09-10 12:09:12 +0000
4@@ -24,6 +24,7 @@
5 from crochet import wait_for_reactor
6 from django.db import (
7 close_old_connections,
8+ connection,
9 transaction,
10 )
11 from maasserver.exceptions import IteratorReusedError
12@@ -151,5 +152,7 @@
13 with transaction.atomic():
14 return func(*args, **kwargs)
15 finally:
16- close_old_connections()
17+ # Close connections if we've left the outer-most atomic block.
18+ if not connection.in_atomic_block:
19+ close_old_connections()
20 return call_within_transaction
21
22=== modified file 'src/maasserver/utils/tests/test_async.py'
23--- src/maasserver/utils/tests/test_async.py 2014-06-13 19:56:48 +0000
24+++ src/maasserver/utils/tests/test_async.py 2014-09-10 12:09:12 +0000
25@@ -127,7 +127,7 @@
26
27 class TestTransactional(MAASTestCase):
28
29- def test_calls_function_within_transaction_then_closes_connections(self):
30+ def test__calls_function_within_transaction_then_closes_connections(self):
31 close_old_connections = self.patch(async, "close_old_connections")
32
33 # No transaction has been entered (what Django calls an atomic
34@@ -158,3 +158,21 @@
35 # been exited, and old connections have been closed.
36 self.assertFalse(connection.in_atomic_block)
37 self.assertThat(close_old_connections, MockCalledOnceWith())
38+
39+ def test__closes_connections_only_when_leaving_atomic_block(self):
40+ close_old_connections = self.patch(async, "close_old_connections")
41+
42+ @async.transactional
43+ def inner():
44+ # We're inside a `transactional` context here.
45+ return "inner"
46+
47+ @async.transactional
48+ def outer():
49+ # We're inside a `transactional` context here too.
50+ # Call `inner`, thus nesting `transactional` contexts.
51+ return "outer > " + inner()
52+
53+ self.assertEqual("outer > inner", outer())
54+ # Old connections have been closed only once.
55+ self.assertThat(close_old_connections, MockCalledOnceWith())