当外部数据库连接失败时,SQLAlchemy 挂起

时间:2021-07-28 21:47:11

标签: sqlalchemy fastapi

在我的应用程序中,我使用内部数据库和外部数据库,其中我使用外部数据库从主/全局数据库加载一些详细信息。

当我尝试查询某些数据或提交事务时,有时会收到错误 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

0 个答案:

没有答案