Browse Source

Don't use wrap_db_retry on subtransaction in resource_create_replacement()

The wrap_db_retry decorator must be used outside the outermost DB
transaction. Using it on a subtransaction means that the main
transaction gets marked for rollback but not closed, leaving the session
in the 'inactive' state.

This change ensures that the decorator is not used when we update the
previous resource from within a subtransaction as part of creating a
replacement resource, and instead the retry happens outside the main
transaction.

Change-Id: I28bfcc43b108d4d907098b2f0cf3553aab399553
Task: 36957
changes/97/688197/1
Zane Bitter 1 month ago
parent
commit
2398191be9
2 changed files with 16 additions and 8 deletions
  1. 12
    4
      heat/db/sqlalchemy/api.py
  2. 4
    4
      heat/tests/db/test_sqlalchemy_api.py

+ 12
- 4
heat/db/sqlalchemy/api.py View File

@@ -265,6 +265,12 @@ def _add_atomic_key_to_values(values, atomic_key):
retry_interval=0.5, inc_retry_interval=True)
def resource_update(context, resource_id, values, atomic_key,
expected_engine_id=None):
return _try_resource_update(context, resource_id, values, atomic_key,
expected_engine_id)


def _try_resource_update(context, resource_id, values, atomic_key,
expected_engine_id=None):
session = context.session
with session.begin(subtransactions=True):
_add_atomic_key_to_values(values, atomic_key)
@@ -453,6 +459,8 @@ def resource_create(context, values):
return resource_ref


@oslo_db_api.wrap_db_retry(max_retries=3, retry_on_deadlock=True,
retry_interval=0.5, inc_retry_interval=True)
def resource_create_replacement(context,
existing_res_id, existing_res_values,
new_res_values,
@@ -463,10 +471,10 @@ def resource_create_replacement(context,
new_res = resource_create(context, new_res_values)
update_data = {'replaced_by': new_res.id}
update_data.update(existing_res_values)
if not resource_update(context,
existing_res_id, update_data,
atomic_key,
expected_engine_id=expected_engine_id):
if not _try_resource_update(context,
existing_res_id, update_data,
atomic_key,
expected_engine_id=expected_engine_id):
data = {}
if 'name' in new_res_values:
data['resource_name'] = new_res_values['name']

+ 4
- 4
heat/tests/db/test_sqlalchemy_api.py View File

@@ -2724,8 +2724,8 @@ class DBAPIResourceReplacementTest(common.HeatTestCase):
db_api.resource_update_and_save(other_ctx, orig.id,
{'atomic_key': 2})

self.patchobject(db_api, 'resource_update',
new=mock.Mock(wraps=db_api.resource_update,
self.patchobject(db_api, '_try_resource_update',
new=mock.Mock(wraps=db_api._try_resource_update,
side_effect=update_atomic_key))

self.assertRaises(exception.UpdateInProgress,
@@ -2767,8 +2767,8 @@ class DBAPIResourceReplacementTest(common.HeatTestCase):
{'engine_id': 'a',
'atomic_key': 2})

self.patchobject(db_api, 'resource_update',
new=mock.Mock(wraps=db_api.resource_update,
self.patchobject(db_api, '_try_resource_update',
new=mock.Mock(wraps=db_api._try_resource_update,
side_effect=lock_resource))

self.assertRaises(exception.UpdateInProgress,

Loading…
Cancel
Save