From 5b36e169ea74d2345545169124c31cdb6c319408 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 24 Oct 2018 10:11:12 -0400 Subject: [PATCH] Add "is_started" flag to enginefacade Some module reloading scenarios such as that which occurs within mod_wsgi mean that an existing module-level enginefacade is already in the "started" state, however initialization routines from the calling application may still attempt to call the ``.configure`` method. Add a new flag is_started to both _TransactionContextManager and _TransactionFactory so that calling code can check for this state ahead of time; additionally, promote the TypeError raised to a specific subclass enginefacade.AlreadyStartedError to allow for better optimistic schemes. Change-Id: I2f5a9e35c2fae0c28b78beef3dcd2c4794362766 References: I704196711d30c1124e713ac31111a8ea6fa2f1ba --- oslo_db/sqlalchemy/enginefacade.py | 21 ++++++++++++++- oslo_db/tests/sqlalchemy/test_enginefacade.py | 26 +++++++++++++++++++ .../add_facade_started-14f9bc34fac89371.yaml | 8 ++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/add_facade_started-14f9bc34fac89371.yaml diff --git a/oslo_db/sqlalchemy/enginefacade.py b/oslo_db/sqlalchemy/enginefacade.py index 481e166e..3618b75f 100644 --- a/oslo_db/sqlalchemy/enginefacade.py +++ b/oslo_db/sqlalchemy/enginefacade.py @@ -120,6 +120,14 @@ class _Default(object): hasattr(conf_namespace, key) +class AlreadyStartedError(TypeError): + """Raises when a factory is being asked to initialize a second time. + + Subclasses :class:`.TypeError` for legacy support. + + """ + + class _TransactionFactory(object): """A factory for :class:`._TransactionContext` objects. @@ -314,7 +322,8 @@ class _TransactionFactory(object): def _configure(self, as_defaults, kw): if self._started: - raise TypeError("this TransactionFactory is already started") + raise AlreadyStartedError( + "this TransactionFactory is already started") not_supported = [] for k, v in kw.items(): for dict_ in ( @@ -464,6 +473,11 @@ class _TransactionFactory(object): if self._reader_engine is not self._writer_engine: self._reader_engine.pool.dispose() + @property + def is_started(self): + """True if this :class:`._TransactionFactory` is already started.""" + return self._started + def _start(self, conf=False, connection=None, slave_connection=None): with self._start_lock: # self._started has been checked on the outside @@ -777,6 +791,11 @@ class _TransactionContextManager(object): """The :class:`._TransactionFactory` associated with this context.""" return self._root._root_factory + @property + def is_started(self): + """True if this manager is already started.""" + return self._factory.is_started + def configure(self, **kw): """Apply configurational options to the factory. diff --git a/oslo_db/tests/sqlalchemy/test_enginefacade.py b/oslo_db/tests/sqlalchemy/test_enginefacade.py index cab7547b..b29a1222 100644 --- a/oslo_db/tests/sqlalchemy/test_enginefacade.py +++ b/oslo_db/tests/sqlalchemy/test_enginefacade.py @@ -479,6 +479,32 @@ class MockFacadeTest(oslo_test_base.BaseTestCase): [mock.call.dispose()] ) + def test_started_flag(self): + facade = enginefacade.transaction_context() + + self.assertFalse(facade.is_started) + facade.configure(connection=self.engine_uri) + facade.writer.get_engine() + + self.assertTrue(facade.is_started) + + def test_started_exception(self): + facade = enginefacade.transaction_context() + + self.assertFalse(facade.is_started) + facade.configure(connection=self.engine_uri) + facade.writer.get_engine() + + exc = self.assertRaises( + enginefacade.AlreadyStartedError, + facade.configure, + connection=self.engine_uri + ) + self.assertEqual( + "this TransactionFactory is already started", + exc.args[0] + ) + def test_session_reader_decorator(self): context = oslo_context.RequestContext() diff --git a/releasenotes/notes/add_facade_started-14f9bc34fac89371.yaml b/releasenotes/notes/add_facade_started-14f9bc34fac89371.yaml new file mode 100644 index 00000000..52154f21 --- /dev/null +++ b/releasenotes/notes/add_facade_started-14f9bc34fac89371.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Added new ``.is_started`` boolean flag to enginefacade context manager + and factory objects, so that double-configure scenarios can be prevented + by calling code. Additionally, the ``TypeError`` raised when configure + is called after the factory is started is now a specific subclass + ``enginefacade.AlreadyStartedError``.