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

Vercel部署FastAPI/SQLModel应用时PostgreSQL表未创建问题

问题:Vercel部署FastAPI+SQLModel应用无法创建PostgreSQL表

我在Vercel上部署基于FastAPI和SQLModel的应用,已在Vercel中正确设置DATABASE_URL环境变量,应用能成功连接Supabase托管的PostgreSQL数据库,但部署过程中数据库表未被创建,仅能与已存在的表交互,无法初始化新的数据库schema。

已执行的排查操作

  • 验证Vercel环境变量中的DATABASE_URL配置正确;
  • 应用在本地运行完全正常,可正常创建表;
  • 确保表创建逻辑已触发,相关代码如下:
    db.py
    from sqlmodel import SQLModel, create_engine
    import os
    
    database_url = os.getenv("DATABASE_URL")
    if not database_url:
        raise ValueError("DATABASE_URL environment variable not set")
    
    #Note: My DATABASE_URL also starts with postgresql://.... and is hosted online
    
    engine = create_engine(database_url)
    
    def init_db():
        SQLModel.metadata.create_all(engine)
    
    main.py
    from fastapi import FastAPI
    import uvicorn
    from contextlib import asynccontextmanager
    from db import engine, init_db
    
    
    @asynccontextmanager
    async def lifespan(app: FastAPI):
        try:
            init_db()
            yield
        finally:
            await engine.dispose()
    
    app = FastAPI(
        lifespan=lifespan)
    
    if __name__ == "__main__":
        uvicorn.run(app)
    
  • 多次重新部署应用,尝试多种触发表创建的方式,但Vercel仍未在PostgreSQL中创建表;
  • 查看Vercel日志,未发现数据库连接或表创建相关错误。

排查建议与解决方法

1. 确认Vercel函数冷启动触发逻辑

Vercel将FastAPI作为Serverless Function运行,lifespan上下文仅在函数首次冷启动时触发。如果应用部署后没有收到任何请求,冷启动不会触发,init_db()也就不会执行。

解决方法:

  • 部署完成后手动发送一个请求到应用(比如访问根路由),触发冷启动执行表初始化;
  • 新增一个可手动触发的初始化接口,部署后调用一次:
    from fastapi import FastAPI
    from db import init_db
    
    app = FastAPI()
    
    @app.get("/init-db")
    def trigger_init_db():
        init_db()
        return {"status": "success", "message": "Database tables initialized"}
    

2. 检查Supabase数据库用户权限

应用能连接数据库不代表拥有创建表的权限,需确认DATABASE_URL中的用户权限:

  • 登录Supabase控制台,进入项目「Database」→「Roles」;
  • 检查对应角色是否拥有public schema的CREATE权限;
  • 权限不足时执行SQL授权:
    GRANT CREATE ON SCHEMA public TO your_db_user;
    

3. 修正同步/异步引擎兼容问题

代码中使用同步create_engine,但在lifespan的finally块调用异步await engine.dispose(),可能引发隐性错误导致初始化中断。

解决方法:

  • 改用SQLModel异步引擎,修改db.py:
    from sqlmodel import SQLModel, create_async_engine
    import os
    
    database_url = os.getenv("DATABASE_URL")
    if not database_url:
        raise ValueError("DATABASE_URL environment variable not set")
    
    # 需提前安装 asyncpg 依赖
    engine = create_async_engine(database_url)
    
    async def init_db():
        async with engine.begin() as conn:
            await conn.run_sync(SQLModel.metadata.create_all)
    
  • 同步修改main.py的lifespan:
    @asynccontextmanager
    async def lifespan(app: FastAPI):
        try:
            await init_db()
            yield
        finally:
            await engine.dispose()
    
  • 在requirements.txt添加依赖:
    asyncpg>=0.29.0
    

4. 部署阶段强制执行初始化

利用Vercel的Build Command,在部署过程中直接执行表初始化:

  • 创建init_db.py脚本:
    from db import init_db
    
    if __name__ == "__main__":
        init_db()
        print("Database tables created successfully")
    
  • 在vercel.json配置构建命令:
    {
        "buildCommand": "python init_db.py && pip install -r requirements.txt"
    }
    
    (若用异步引擎,需将脚本改为异步执行,比如用asyncio.run(init_db()))

5. 增加日志排查

在init_db()中添加详细日志,确认执行状态:
修改db.py:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def init_db():
    logger.info("Starting database table initialization...")
    try:
        SQLModel.metadata.create_all(engine)
        logger.info("Database tables created successfully")
    except Exception as e:
        logger.error(f"Error creating tables: {str(e)}", exc_info=True)

部署后查看Vercel函数日志,确认是否有相关输出。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:23:10