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

Mongoose抛出错误致程序崩溃,错误处理无效求助

环境信息

  • Mongoose版本:6.3.4
  • Node.js版本:18.6.0
  • MongoDB版本:4.4
  • 操作系统:Linux
  • 操作系统版本:20.04

问题描述

Mongoose抛出错误时会导致程序直接退出崩溃。已经添加了基础错误处理,但程序仍会崩溃,推测存在未捕获的错误但无法定位具体位置。

数据库模块代码

import { Console } from 'console'
import mongoose from 'mongoose'
import Logger from '../util/logger'

const logger = new Logger(`Worker/${process.pid}/database/site`)

const schemas = {
  sitemeta: new mongoose.Schema({
    setting: { type: String },
    data: { type: Object }
  }, { collection: 'site-meta' }),
  project: new mongoose.Schema({
    project_name: { type: String },
    description: { type: String },
    project_short_name: { type: String },
    side_project: { type: Boolean },
    project_body: { type: String },
    thumbnail_source: { type: String }
  }, { collection: 'projects' }),
  admin: new mongoose.Schema({
    key_hash: { type: String },
    key_identifier: { type: String }
  }, { collection: 'admins' })
}

async function dbConnect () {
  try {
    await mongoose.connect(process.env.MONGODB!, { dbName: 'site' })
    mongoose.connection
      .on('error', () => logger.error('db error occured'))
      .once('open', () => logger.log('Connected to database'))
  } catch {
    logger.error('DB connect fail')
  }
}

dbConnect()

const SiteMeta = mongoose.model('site-meta', schemas.sitemeta)
const Project = mongoose.model('projects', schemas.project)
const Admin = mongoose.model('admins', schemas.admin)

export { SiteMeta, Project, Admin }

测试场景与错误日志

关闭MongoDB实例后启动应用,控制台先输出DB connect fail(说明catch块已触发),但随后程序仍崩溃,完整日志如下:

[ERROR] [08/08/2022, 03:46:14][wonik-website-core/Worker/8955/database/site] DB connect fail
/home/myusr/website-core/node_modules/mongodb/src/sdam/topology.ts:606
        const timeoutError = new MongoServerSelectionError(
                             ^
MongoServerSelectionError: connect ECONNREFUSED MYIP:PORT
    at Timeout._onTimeout (/home/myusr/website-core/node_modules/mongodb/src/sdam/topology.ts:606:30)
    at listOnTimeout (node:internal/timers:564:17)
    at processTimers (node:internal/timers:507:7) {
  reason: TopologyDescription {
    type: 'Unknown',
    servers: Map(1) { 'wonik-server.ddns.net:4823' => [ServerDescription] },
    stale: false,
    compatible: true,
    heartbeatFrequencyMS: 10000,
    localThresholdMS: 15,
    logicalSessionTimeoutMinutes: undefined
  },
  code: undefined,
  [Symbol(errorLabels)]: Set(0) {}
}
[nodemon] app crashed - waiting for file changes before starting...

解决方案

问题根源是:mongoose.connect的try/catch仅能捕获初始连接阶段的同步/立即错误,而底层MongoDB驱动在后续拓扑检测时的异步错误会以未处理Promise拒绝的形式抛出,导致程序崩溃。可以通过以下步骤解决:

  1. 全局捕获未处理的Promise拒绝
    在应用入口或数据库模块中添加全局监听,拦截所有未捕获的Promise错误,避免程序直接退出:
process.on('unhandledRejection', (reason, promise) => {
  logger.error(`未处理的Promise拒绝: ${reason instanceof Error ? reason.message : reason}`);
  // 可选:添加重连逻辑或告警通知
});
  1. 完善Mongoose连接的错误处理
    扩展dbConnect函数的错误处理逻辑,同时为连接实例添加更详细的错误监听,并可选添加重连机制:
async function dbConnect () {
  try {
    await mongoose.connect(process.env.MONGODB!, { 
      dbName: 'site',
      serverSelectionTimeoutMS: 5000 // 设置连接超时时间,避免驱动长时间重试
    });
    mongoose.connection
      .on('error', (err) => {
        logger.error(`数据库连接错误: ${err.message}`);
        // 可选:触发重连
        setTimeout(dbConnect, 5000);
      })
      .once('open', () => logger.log('Connected to database'));
  } catch (err) {
    logger.error(`DB连接失败: ${err instanceof Error ? err.message : err}`);
    // 连接失败后自动重试
    setTimeout(dbConnect, 5000);
  }
}

通过以上处理,既能捕获初始连接错误,也能拦截驱动层面的异步拓扑错误,避免程序因未处理的Promise拒绝崩溃。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:06:19