在我的应用程序中,我使用内部数据库和外部数据库,其中我使用外部数据库从主/全局数据库加载一些详细信息。
当我尝试查询某些数据或提交事务时,有时会收到错误 sqlalchemy.exc.InvalidRequestError: Can't reconnect until invalid transaction is rolled back
,这会导致整个应用程序崩溃,并且在我重新启动它之前无法修复。这主要发生在重新启动外部数据库时。我们失去了连接,交易无效并挂起。
在 FastAPI 应用程序中,我使用 SQLAlchemy。我将外部数据库设置如下(省略了一些多余的细节):
class _ExternalDB(DBSetup):
def __init__(self):
self._database = Database(self.url, ssl=ctx)
self._engine = create_engine(self.url, echo=True, echo_pool='debug')
self._session = scoped_session(
sessionmaker(autocommit=False, autoflush=False, bind=self._engine, class_=SafeSession)
)
其中 DBSetup
是包含 url、数据库和会话的基类。我编写了 SafeSession 类来尝试解决我遇到的问题:
class SafeSession(Session):
def commit(self):
try:
return super().commit()
except Exception as e:
logger.error("Could not commit the SQL operation!", e)
self.rollback()
raise e
def query(self, *entities, **kwargs):
try:
return super().query(*entities, **kwargs)
except Exception as e:
logger.error("Could not complete the transaction!", e)
self.rollback()
raise e
示例查询如下:
external_db_setup.session.query(User).get(user_id)
我的目标是在无效事务发生时将其回滚,但应用程序永远不会到达 except 块,因为我从未看到任何“无法完成事务”的日志。我错过了什么吗?
完整的错误日志:
File "/***/repositories/user.py", line 8, in get_user_by_id
return external_db_setup.session.query(User).get(user_id)
File "/***/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 1004, in get
return self._get_impl(ident, loading.load_on_pk_identity)
File "/***/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 1119, in _get_impl
return db_load_fn(self, primary_key_identity)
File "/***/lib/python3.8/site-packages/sqlalchemy/orm/loading.py", line 284, in load_on_pk_identity
return q.one()
File "/***/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3358, in one
ret = self.one_or_none()
File "/***/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3327, in one_or_none
ret = list(self)
File "/***/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3403, in __iter__
return self._execute_and_instances(context)
File "/***/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3428, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/***/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 984, in execute
return meth(self, multiparams, params)
File "/***/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 293, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/***/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1097, in _execute_clauseelement
ret = self._execute_context(
File "/***/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1177, in _execute_context
self._handle_dbapi_exception(
File "/***/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1481, in _handle_dbapi_exception
util.raise_(
File "/***/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 178, in raise_
raise exception
File "/***/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1173, in _execute_context
conn = self._revalidate_connection()
File "/***/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 456, in _revalidate_connection
raise exc.InvalidRequestError(
graphql.error.located_error.GraphQLLocatedError: (sqlalchemy.exc.InvalidRequestError) Can't reconnect until invalid transaction is rolled back