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

如何让Node服务等待MongoDB启动并实现重连(PM2场景)

解决PM2 Reload时Node服务连接MongoDB失败的问题

嘿,这个场景我太熟悉了!PM2 reload的时候确实会打乱服务启动的顺序,MongoDB需要一点时间完成初始化,但Node服务重启后会立刻尝试连接,结果就扑空了。不过咱们可以从Node端入手,让服务在连接失败时自动重试,结合MongoDB驱动的特性或者自定义逻辑就能搞定,我给你两种实用方案:

方案一:利用MongoDB驱动内置的重连机制

MongoDB官方驱动本身就支持自动重连,只要在创建客户端时配置相关参数,就能让驱动在连接失败时自动重试,不用自己写太多逻辑。示例代码如下:

const { MongoClient } = require('mongodb');
const express = require('express');

// MongoDB连接字符串
const mongoUri = 'mongodb://localhost:27017/your-database-name';

// 配置MongoDB客户端的重连参数
const mongoClient = new MongoClient(mongoUri, {
  retryWrites: true,
  reconnectTries: Number.MAX_VALUE, // 设置为无限重试(直到成功)
  reconnectInterval: 1500, // 每次重试间隔1.5秒
  connectTimeoutMS: 30000, // 单次连接超时时间
  socketTimeoutMS: 30000 // 套接字超时时间
});

async function initApp() {
  try {
    // 尝试连接MongoDB
    await mongoClient.connect();
    console.log('✅ 成功连接到MongoDB');
    
    // 连接成功后再启动Express服务
    startExpressServer(mongoClient);
  } catch (error) {
    console.error('❌ 初始连接MongoDB失败,驱动将自动重试:', error.message);
    // 这里可以加个兜底的手动重试,防止驱动的自动重试出意外
    setTimeout(initApp, 5000);
  }
}

function startExpressServer(client) {
  const app = express();
  
  // 将MongoDB客户端挂载到app上,方便路由中使用
  app.locals.mongoClient = client;
  
  // 示例路由
  app.get('/', (req, res) => {
    res.send('服务正常运行,已连接MongoDB');
  });
  
  // 启动Express服务
  app.listen(3000, () => {
    console.log('🚀 Express服务已启动在端口3000');
    // 如果用PM2的wait_ready配置,记得发送ready信号
    process.send?.('ready');
  });
}

// 初始化应用
initApp();

关键参数说明:

  • reconnectTries: Number.MAX_VALUE:让驱动无限重试连接,直到成功
  • reconnectInterval: 1500:每次重试的间隔时间,避免过于频繁重试
  • connectTimeoutMS和socketTimeoutMS:设置合理的超时时间,防止单次连接卡住太久

方案二:自定义连接重试逻辑(更灵活可控)

如果你需要更精细的控制(比如限制重试次数、添加告警逻辑),可以自己封装一个带重试的连接函数:

const { MongoClient } = require('mongodb');
const express = require('express');

const mongoUri = 'mongodb://localhost:27017/your-database-name';
const MAX_RETRIES = 12; // 最多重试12次(约24秒)
const RETRY_INTERVAL = 2000; // 每次重试间隔2秒

async function connectMongoWithRetry(retryCount = 0) {
  const client = new MongoClient(mongoUri);
  
  try {
    await client.connect();
    return client;
  } catch (error) {
    console.error(`⚠️ 连接失败,重试次数: ${retryCount + 1}/${MAX_RETRIES}`, error.message);
    
    if (retryCount < MAX_RETRIES) {
      // 等待指定间隔后重试
      await new Promise(resolve => setTimeout(resolve, RETRY_INTERVAL));
      return connectMongoWithRetry(retryCount + 1);
    } else {
      // 达到最大重试次数,终止服务或触发告警
      console.error('❌ 达到最大重试次数,无法连接MongoDB,服务终止');
      process.exit(1);
    }
  }
}

async function startApp() {
  try {
    const mongoClient = await connectMongoWithRetry();
    console.log('✅ MongoDB连接成功');
    
    const app = express();
    app.locals.mongoClient = mongoClient;
    
    app.get('/', (req, res) => {
      res.send('服务正常运行,已连接MongoDB');
    });
    
    app.listen(3000, () => {
      console.log('🚀 Express服务已启动在端口3000');
      process.send?.('ready');
    });
  } catch (error) {
    console.error('❌ 应用启动失败:', error);
  }
}

startApp();

这种方式的优势是可以完全掌控重试的节奏和终止条件,比如重试12次后还失败就退出服务,避免无限等待。

额外的PM2配置优化

除了Node端的重试逻辑,还可以优化PM2的配置文件(ecosystem.config.js),让PM2更智能地处理服务启动顺序:

module.exports = {
  apps: [
    {
      name: 'mongodb',
      script: 'mongod',
      args: '--dbpath ./data/db', // 替换成你的MongoDB数据路径
      autorestart: true,
      out_file: './logs/mongodb-out.log',
      error_file: './logs/mongodb-error.log'
    },
    {
      name: 'express-server',
      script: './server.js', // 你的Node服务入口文件
      autorestart: true,
      wait_ready: true, // 等待服务发送ready信号才标记为就绪
      listen_timeout: 60000, // 最多等待60秒
      out_file: './logs/express-out.log',
      error_file: './logs/express-error.log',
      env: {
        NODE_ENV: 'development'
      }
    }
  ]
};

配合前面代码中的process.send('ready'),PM2会等到Express服务真正连接上Mongo并启动后,才会认为服务就绪,避免过早重启或者误判服务状态。

这样一来,不管是pm2 start all还是pm2 reload all,Node服务都会耐心等待MongoDB初始化完成,再也不会因为连接失败而直接挂掉了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:11:43