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
=== modified file 'src/maasserver/utils/async.py'
--- src/maasserver/utils/async.py 2014-08-13 21:49:35 +0000
+++ src/maasserver/utils/async.py 2014-09-10 12:09:12 +0000
@@ -24,6 +24,7 @@
24from crochet import wait_for_reactor24from crochet import wait_for_reactor
25from django.db import (25from django.db import (
26 close_old_connections,26 close_old_connections,
27 connection,
27 transaction,28 transaction,
28 )29 )
29from maasserver.exceptions import IteratorReusedError30from maasserver.exceptions import IteratorReusedError
@@ -151,5 +152,7 @@
151 with transaction.atomic():152 with transaction.atomic():
152 return func(*args, **kwargs)153 return func(*args, **kwargs)
153 finally:154 finally:
154 close_old_connections()155 # Close connections if we've left the outer-most atomic block.
156 if not connection.in_atomic_block:
157 close_old_connections()
155 return call_within_transaction158 return call_within_transaction
156159
=== modified file 'src/maasserver/utils/tests/test_async.py'
--- src/maasserver/utils/tests/test_async.py 2014-06-13 19:56:48 +0000
+++ src/maasserver/utils/tests/test_async.py 2014-09-10 12:09:12 +0000
@@ -127,7 +127,7 @@
127127
128class TestTransactional(MAASTestCase):128class TestTransactional(MAASTestCase):
129129
130 def test_calls_function_within_transaction_then_closes_connections(self):130 def test__calls_function_within_transaction_then_closes_connections(self):
131 close_old_connections = self.patch(async, "close_old_connections")131 close_old_connections = self.patch(async, "close_old_connections")
132132
133 # No transaction has been entered (what Django calls an atomic133 # No transaction has been entered (what Django calls an atomic
@@ -158,3 +158,21 @@
158 # been exited, and old connections have been closed.158 # been exited, and old connections have been closed.
159 self.assertFalse(connection.in_atomic_block)159 self.assertFalse(connection.in_atomic_block)
160 self.assertThat(close_old_connections, MockCalledOnceWith())160 self.assertThat(close_old_connections, MockCalledOnceWith())
161
162 def test__closes_connections_only_when_leaving_atomic_block(self):
163 close_old_connections = self.patch(async, "close_old_connections")
164
165 @async.transactional
166 def inner():
167 # We're inside a `transactional` context here.
168 return "inner"
169
170 @async.transactional
171 def outer():
172 # We're inside a `transactional` context here too.
173 # Call `inner`, thus nesting `transactional` contexts.
174 return "outer > " + inner()
175
176 self.assertEqual("outer > inner", outer())
177 # Old connections have been closed only once.
178 self.assertThat(close_old_connections, MockCalledOnceWith())