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

NestJS+Prisma双客户端部署时出现‘Server has closed the connection’问题

解决Prisma+NestJS搭配pgBouncer主从PostgreSQL的连接关闭问题

核心问题定位

上线后出现的「Server has closed the connection」错误,本质是pgBouncer连接池配置与Prisma客户端连接管理不匹配,加上连接字符串的语法错误共同导致的。以下是具体排查和修复方案:

1. 修正连接字符串的语法错误

查看你的DATABASE_READ_URL配置,发现密码后多了一个多余的@符号:

DATABASE_READ_URL="postgresql://user:******:@[replicaip]:5432/stage-v2-panel?schema=public&pgbouncer=true"

改为:

DATABASE_READ_URL="postgresql://user:******@[replicaip]:5432/stage-v2-panel?schema=public&pgbouncer=true"

这个语法错误可能导致连接建立不稳定,是触发问题的潜在因素。

2. 调整pgBouncer的连接池配置

pgBouncer的默认参数会主动回收长期闲置的连接,而Prisma客户端如果持有这些被回收的连接,就会触发报错。修改pgBouncer的pgbouncer.ini配置:

  • 设置server_lifetime = 86400(1天):延长pgBouncer与PostgreSQL服务器的连接存活时间,避免频繁关闭连接
  • 启用pool_mode = transaction:事务模式下,pgBouncer会在每个事务结束后回收连接,更适配Prisma的ORM操作模式
  • 确保default_pool_size和max_client_conn足够大:根据业务并发量调整,避免因连接池耗尽导致的连接关闭

3. 优化Prisma客户端的连接管理

当前的PrismaService主动调用$connect()会长期持有连接,容易被pgBouncer回收,同时缺少错误重试和重连机制。修改你的PrismaService:

@Injectable()
export class PrismaService implements OnModuleDestroy {
  readClient: PrismaClient;
  writeClient: PrismaClient;

  constructor() {
    this.readClient = this.createPrismaClient(process.env.DATABASE_READ_URL);
    this.writeClient = this.createPrismaClient(process.env.DATABASE_WRITE_URL);
    this.setupConnectionRecovery();
  }

  private createPrismaClient(url: string): PrismaClient {
    return new PrismaClient({
      datasources: { db: { url } },
      retry: {
        maxRetries: 3,
        retryDelay: 100,
        retryableErrors: ['Server has closed the connection']
      }
    });
  }

  private setupConnectionRecovery(): void {
    // 处理读客户端连接错误
    this.readClient.$on('error', async (e) => {
      if (e.message.includes('Server has closed the connection')) {
        await this.readClient.$disconnect();
        this.readClient = this.createPrismaClient(process.env.DATABASE_READ_URL);
      }
    });

    // 处理写客户端连接错误
    this.writeClient.$on('error', async (e) => {
      if (e.message.includes('Server has closed the connection')) {
        await this.writeClient.$disconnect();
        this.writeClient = this.createPrismaClient(process.env.DATABASE_WRITE_URL);
      }
    });
  }

  async onModuleDestroy() {
    await this.readClient.$disconnect();
    await this.writeClient.$disconnect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.readClient.$on('beforeExit', async () => {
      await app.close();
    });
    this.writeClient.$on('beforeExit', async () => {
      await app.close();
    });
  }
}

关键优化点:

  • 移除onModuleInit中的$connect()调用,让Prisma按需建立连接,避免长期持有闲置连接
  • 添加自动重试机制,对连接关闭错误自动重试3次
  • 监听连接错误事件,当检测到连接关闭时,自动断开并重新创建客户端实例
  • 实现OnModuleDestroy接口,在模块销毁时主动断开连接,避免资源泄漏

4. 主从架构额外检查

  • 确认从库的复制延迟在可接受范围内,避免因数据不一致引发的间接错误
  • 确保主从库的pgBouncer配置完全一致,避免因配置差异导致的连接行为不一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 03:30:55