You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI将数据库连接存入app.state时的连接存活与共享问题

问题场景

我使用psycopg2连接postgresql数据库,为避免每次与数据库交互都新建连接,我在服务启动阶段创建单个连接,存储在app.state中,实现代码如下:

def startup(app: FastAPI) -> Callable:
    """
    :param app: FastAPI
    :return: start_app
    """
    def app_start() -> None:
        
        # create a new connection
        conn = get_conn()
        # store the connection
        app.state.conn = conn
        app.state.cur = cur

    return app_start

# register startup func 
app.add_event_handler("startup", startup(app))

调用连接的方式:

request.app.state.conn

我有两个疑问:

  1. 存储在app.state中的conn实际运行状态是怎样的?该连接是否会持续保持存活?还是会超时自动断开,且FastAPI调用时会自动新建连接?
  2. conn变量是否会在多线程之间共享?还是FastAPI会为不同线程分别创建新连接分配?

回答

关于连接存活状态的问题

app.state只是FastAPI提供的一个全局属性挂载容器,不会对挂载的对象做任何额外处理,你存进去的psycopg2连接就是普通的Python连接实例:

  • 没有主动触发断开、网络链路正常、PostgreSQL服务端没有主动踢掉空闲连接的前提下,这个连接会一直保持存活,可以正常执行SQL。
  • 一旦连接因为服务端空闲超时、防火墙/Nginx等中间节点的空闲连接回收策略断开,FastAPI完全不会感知到这个变化,绝对不会自动帮你新建连接,下次用这个断开的实例执行SQL时会直接抛出psycopg2.OperationalError类的连接异常。
  • 额外提一句你代码里的明显问题:app.state.cur = cur中的cur变量没有在app_start作用域内定义,启动时会直接抛NameError,而且不建议全局挂载游标对象,游标会保留上次查询的状态,跨请求复用很容易出现结果错乱。

关于多线程共享的问题

app.state是服务进程内的全局单例,你挂载的conn会被该进程内所有处理请求的线程/协程共享,FastAPI不会为不同线程/请求自动创建新连接:

  • psycopg2的同步连接本身不支持多线程并发操作,多线程同时复用同一个连接执行SQL,会出现查询结果串扰、连接内部状态损坏、事务错乱等问题,生产环境这么写必然出故障。
  • 就算是异步驱动的数据库连接,同一时间单个连接也只能处理一个查询,并发场景下全局单连接会直接成为性能瓶颈。

可行的修正方案

不要用全局单连接的方案,改用数据库连接池:

  • 同步场景下直接使用psycopg2.pool.ThreadedConnectionPool,在启动事件中初始化连接池挂载到app.state,每个请求进入时从池里申请一个连接,请求处理完成后把连接还给连接池。
  • 如果用多worker模式部署FastAPI(比如Gunicorn启动多个UvicornWorker),每个worker是独立进程,会各自初始化自己的连接池,不需要做跨进程的连接共享。
  • 成熟的连接池实现一般自带空闲连接校验、断开重连、最大连接数限制能力,不需要你手动处理连接保活、断连重试的逻辑。

内容的提问来源于stack exchange,提问作者IMAPOTATO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:12:28