From 2d8986bda4fd96f3aa177589a8a272e3d1f455d5 Mon Sep 17 00:00:00 2001 From: Julia Kreger <juliaashleykreger@gmail.com> Date: Thu, 20 Jul 2023 11:01:00 -0700 Subject: [PATCH] Fix retry logic logging logging has a method debug, and a static variable DEBUG, which are entirely different. Tenacity requires the integer value which is passed in for logging actions. This is rooted in the examples published on tenacity logging, since the lower level caller doesn't log in many cases, and our testing didn't catch this precise case because we were only validating that logging was called, not that logging worked. We also didn't see any of the errors related to CI resource contention being lessened when the patch was running, and many of the chances of lock conflicts being reduced in other fixes. Duplicates the retry test *without* the logging mock, as not mocking the logging would have yielded the break. Change-Id: I4a65a044e90aff3cffae24f191e425bc75b5fb74 --- ironic/db/sqlalchemy/api.py | 2 +- ironic/tests/unit/db/test_nodes.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ironic/db/sqlalchemy/api.py b/ironic/db/sqlalchemy/api.py index 5c976e8152..05b50d11dc 100644 --- a/ironic/db/sqlalchemy/api.py +++ b/ironic/db/sqlalchemy/api.py @@ -85,7 +85,7 @@ def wrap_sqlite_retry(f): multiplier=0.25, max=CONF.database.sqlite_max_wait_for_retry), before_sleep=( - tenacity.before_sleep_log(LOG, logging.debug) + tenacity.before_sleep_log(LOG, logging.DEBUG) ), reraise=True): with attempt: diff --git a/ironic/tests/unit/db/test_nodes.py b/ironic/tests/unit/db/test_nodes.py index ba93ec7122..3dee718eb1 100644 --- a/ironic/tests/unit/db/test_nodes.py +++ b/ironic/tests/unit/db/test_nodes.py @@ -879,6 +879,26 @@ class DbNodeTestCase(base.DbTestCase): self.assertEqual(3, mock_update.call_count) self.assertEqual(2, log_mock.log.call_count) + def test_update_node_retries_without_log_mock(self): + """Test retry logic to ensure it works.""" + node = utils.create_test_node() + CONF.set_override('sqlite_retries', True, group='database') + # NOTE(TheJulia): Update is an ideal place to test retries + # as the underlying work is done by _do_update_node. + with mock.patch.object(db_conn, '_do_update_node', + autospec=True) as mock_update: + sa_err = sa_exc.OperationalError( + statement=None, + params=None, + orig=Exception('database is locked')) + mock_update.side_effect = [ + sa_err, + sa_err, + node + ] + self.dbapi.update_node(node.id, {'extra': {'foo': 'bar'}}) + self.assertEqual(3, mock_update.call_count) + def test_update_node_uuid(self): node = utils.create_test_node() self.assertRaises(exception.InvalidParameterValue,