Nestjs+Prisma+MongoDB偶发ConnectorError(os error 10054)求助
偶发Prisma ConnectorError(os error 10054)问题排查与解决
我正在使用NestJS和MongoDB开发API,遇到一个出现频率极低的偶发问题:调用this.prisma.people.findMany()时触发ConnectorError,错误信息如下:
{ "status": "error", "message": "\nInvalid this.prisma.people.findMany() invocation in\nC:\\ima\\empresas\\datec\\api-official\\src\\modules\\Events\\services\\utils.service.ts:57: 28\n\n 54 }),\n 55 \n 56 // Get attendees by id\n→ 57 this.prisma.people.findMany(\nError in batch request 3: Error occurred during query execution:\nConnectorError(ConnectorError { user_facing_error: None, kind: RawDatabaseError { code: \"unknown\", message: \"An existing connection was forced to be terminated by the remote host. (os error 10054)\" } })\n" }
我已按照NestJS集成Prisma的官方文档步骤操作,但仍未找到有效的解决方法,以下是相关代码实现:
Prisma Service实现
// Librarys import { Injectable } from '@nestjs/common' import { PrismaClient } from '@prisma/client' // Interfaces import { INestApplication, OnModuleInit, OnModuleDestroy } from '@nestjs/common' @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { async onModuleInit() { await this.$connect() } async onModuleDestroy() { await this.$disconnect() } async enableShutdownHooks(app: INestApplication) { this.$on('beforeExit', async () => { await app.close() }) } }
应用启动文件
// Libraries import { NestFactory } from '@nestjs/core' import { ValidationPipe } from '@nestjs/common' import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger' import { useContainer } from 'class-validator' // Modules import { MainModule } from './main.module' // config import pk from '@root/package.json' import { corstOptions } from '@config/cors' import { PORT, APP_NAME, PUBLIC_URL } from '@config/env' // Exceptions import { HttpExceptionFilter } from '@utils/HttpExceptionFilter' import { PrismaService } from '@root/src/services/prisma' async function bootstrap() { // Create application const app = await NestFactory.create(MainModule) // Enable cors app.enableCors(corstOptions) // Use global 'api' prefix, all calls will come after '/api/*' app.setGlobalPrefix('api') // Globally define custom response app.useGlobalFilters(new HttpExceptionFilter()) // Enable prism on custom validations useContainer(app.select(MainModule), { fallbackOnErrors: true }) // Get service from primsa and enable 'shutdowns' const prismaService = app.get(PrismaService) await prismaService.enableShutdownHooks(app) // Use 'pipe' validation to validate the 'body' structure app.useGlobalPipes( new ValidationPipe({ whitelist: true, transform: true, forbidUnknownValues: true, forbidNonWhitelisted: true, transformOptions: { enableImplicitConversion: true } }) ) // Create API documentation const config = new DocumentBuilder() .addBearerAuth() .setTitle(`API | ${APP_NAME}`) .setContact(pk.author.name, pk.author.url, pk.author.email) .setDescription(pk.description) .setVersion(pk.version) .build() const document = SwaggerModule.createDocument(app, config) SwaggerModule.setup('/', app, document) // Listen to the application on the PORT defined in the environment variables await app.listen(PORT || 0, () => { // eslint-disable-next-line no-console console.log( '\x1b[33m%s\x1b[0m', `[INFO] The server has been started at '${PUBLIC_URL}'` ) }) } bootstrap() // Run application
Event模块UtilsService
// Librarys import { Prisma } from '@prisma/client' import { Inject, Injectable } from '@nestjs/common' // Services import { PrismaService } from '@services/prisma' // DTO import { EventBodyDTO } from '@modules/Events/events.dto' // Arguments import { EventsArgs } from '@modules/Events/events.args' @Injectable() export class UtilsService { @Inject(PrismaService) private readonly prisma: PrismaService private readonly selects = { 'id.title': { id: true, title: true }, 'id.fullname': { id: true, fullname: true }, 'id.title.attributes': { id: true, title: true, attributes: true }, 'id.code.description.attributes': { id: true, code: true, description: true, attributes: true } } /** * Get reminders, types of activities, case, client and attendees of an event * @param {EventBodyDTO} payload Event data */ async getEventFields(payload: EventBodyDTO) { const [activityType, eventCase, client, assistants, reminders] = await Promise.all([ // Get an activity type by id this.prisma.parameters.findUnique({ select: this.selects['id.title'], where: { id: payload.activityType } }), // Get a case by id this.prisma.expedients.findUnique({ where: { id: payload.case }, select: this.selects['id.code.description.attributes'] }), // Get a person by id this.prisma.people.findFirst({ select: this.selects['id.fullname'], where: { isClient: true, id: payload.client } }), // Get attendees by id this.prisma.people.findMany({ select: this.selects['id.fullname'], where: { isEmployee: true, id: { in: payload.assistants } } }), // Get reminders by id this.prisma.parameters.findMany({ select: this.selects['id.title.attributes'], where: { id: { in: payload.reminders } } }) ]) return { reminders: reminders, assistants: assistants, client: client === null ? {} : client, case: eventCase === null ? {} : eventCase, activityType: activityType === null ? {} : activityType } } /** * Create filters to filter by customer or event attendees * @param {EventsArgs} args Arguments to filter * @returns {Promise<Prisma.EventsFindManyArgs['where']>} Returns an object with filters */ async createEventFilters( args: EventsArgs ): Promise<Prisma.EventsFindManyArgs['where']> { const filters: Prisma.EventsFindManyArgs['where'] = { userId: args.user } // Filter by customer if (typeof args.client === 'string') { const clients = await this.prisma.people.findMany({ where: { isClient: true, fullname: { mode: 'insensitive', contains: args.client } }, select: { id: true, fullname: true } }) filters.OR = [] for (const client of clients) { filters.OR.push({ client: { equals: client.id } }) } } // Filter by attendees if (Array.isArray(args.assistants)) { const assistants = await this.prisma.people.findMany({ where: { isEmployee: true, id: { in: args.assistants } }, select: { id: true, fullname: true } }) if (!Array.isArray(filters.OR)) { filters.OR = [] } filters.OR.push({ assistants: { hasSome: assistants.map(item => item.id) } }) } return filters } }
问题分析与解决建议
核心错误原因:
os error 10054表示远程主机强制关闭了现有连接,通常是MongoDB主动断开了闲置的连接,而Prisma连接池中的连接未被及时回收或重建。具体修复方案:
- 调整Prisma连接池配置:在
schema.prisma中添加连接超时和闲置超时参数,让Prisma主动回收闲置连接:datasource db { provider = "mongodb" url = env("DATABASE_URL") pool_timeout = 30 // 连接池获取连接超时时间(秒) idle_timeout = 60 // 连接闲置超时时间(秒),需小于MongoDB的maxIdleTimeMS } - 添加连接重试机制:在全局异常过滤器中捕获
ConnectorError,针对查询请求进行最多2-3次重试,避免偶发错误导致请求失败。 - 修复代码语法错误:修正原代码中的拼写错误、括号缺失、查询条件匹配错误等问题,消除潜在的逻辑异常。
- 检查MongoDB配置:确认MongoDB的
maxIdleTimeMS、socketTimeoutMS等参数,确保Prisma的idle_timeout小于MongoDB的闲置超时阈值,避免连接被主动断开。
- 调整Prisma连接池配置:在
内容的提问来源于stack exchange,提问作者Husdady
相关产品推荐
相关产品推荐

