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

NestJS+Prisma+PostgreSQL生产环境数据库恢复模式报错求助

解决PostgreSQL处于恢复模式导致Prisma查询失败的问题

错误本质

日志中的FATAL: the database system is in recovery mode说明你的PostgreSQL实例正处于恢复状态,无法正常处理查询请求。这种情况通常由数据库崩溃、主从同步异常、资源不足或磁盘问题引发。

排查与解决步骤

1. 检查PostgreSQL容器状态与日志

  • 查看数据库容器的详细日志,定位恢复触发原因:
    docker logs <你的PostgreSQL容器名或ID>
    
  • 检查容器是否频繁重启:
    docker ps -a
    
    日志中可能会出现崩溃报错、磁盘空间不足或WAL日志异常等信息。

2. 确认数据库连接目标

  • 如果是主从集群部署,确保应用连接的是主库:从库在同步主库数据时会进入recovery模式,仅支持只读操作(部分场景下甚至只读也受限),若误连从库会导致查询失败。
  • 核对Prisma配置文件中的DATABASE_URL,确认主机地址、端口指向正确的数据库实例。

3. 修复单实例数据库的恢复状态

  • 进入PostgreSQL容器,检查恢复进度:
    docker exec -it <postgres-container-name> pg_controldata /var/lib/postgresql/data
    
    查看Latest checkpoint location和Recovery target location判断恢复是否在正常推进。
  • 若恢复卡住或失败,优先检查磁盘空间:
    docker exec <postgres-container-name> df -h
    
    磁盘满会导致数据库崩溃,清理空间后重启容器;若WAL日志损坏,需从最近的备份恢复数据库。

4. 优化Docker部署配置

  • 给PostgreSQL容器分配足够的内存和CPU:资源不足会导致数据库频繁崩溃触发恢复,可在docker-compose.yml中添加资源限制:
    services:
      postgres:
        image: postgres:15
        resources:
          limits:
            memory: 2G
            cpus: '1.5'
    
  • 确保数据卷权限正确:PostgreSQL进程需要读写权限,主机挂载目录需设置为postgres用户(UID=999):
    chown -R 999:999 /主机路径/postgres-data
    
  • 调整Prisma连接池参数:在schema.prisma中设置合理的连接数,避免连接池耗尽压垮数据库:
    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
      shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
      pool_size = 10 # 根据实例资源调整,默认是5
    }
    

5. 代码层面添加容错重试

在Prisma查询处添加重试逻辑,避免数据库短暂恢复时直接返回错误给用户:

// wallpaper.menu.repository.ts
async list(sortOptions?: any[]) {
  const newSortOptions = sortOptions
    ? [{ orderBy: 'page', order: 'asc' }, ...sortOptions]
    : [{ orderBy: 'page', order: 'asc' }];
  
  const maxRetries = 3;
  let currentRetry = 0;

  while (currentRetry < maxRetries) {
    try {
      return await this.menuRepository.findMany({
        orderBy: newSortOptions
      });
    } catch (error) {
      currentRetry++;
      // 仅针对recovery模式错误进行重试
      if (error.message.includes('the database system is in recovery mode') && currentRetry < maxRetries) {
        await new Promise(resolve => setTimeout(resolve, 1000)); // 间隔1秒重试
        continue;
      }
      throw error;
    }
  }

  throw new Error('数据库处于恢复模式,重试次数耗尽');
}

内容的提问来源于stack exchange,提问作者Tuấn Vũ Quý

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:46:09