【问题标题】:Cannot connect Node to mongoDB in docker container on first try第一次尝试无法将节点连接到 docker 容器中的 mongoDB
【发布时间】:2020-10-13 07:55:41
【问题描述】:

我正在尝试对使用 mongoose 连接到 MongoDB 的 Node.js 应用程序进行 dockerize。当连接 URL 为:mongodb://localhost:27017/deposit 时,只要我从 shell 运行node index.js,它就会成功。 如果我重新启动计算机,然后尝试使用命令 docker-compose up 运行 dockerized 项目(在 url 中使用 mongo 而不是 localhost),它将无法连接到 MongoDB。但是在我再次尝试相同的命令后,它就成功了。

所以我的问题是为什么节点在计算机重启后第一次尝试无法连接到 MongoDB?

附言。 Docker 在我尝试时正在运行

connection.js

const mongoose = require('mongoose');

const connection = "mongodb://mongo:27017/deposit";

const connectDb = () => {
    mongoose.connect(connection, {useNewUrlParser: true,  useUnifiedTopology: true}).then(res => console.log("Connected to DB"))
    .catch(err => console.log('>> Failed to connect to MongoDB, retrying...'));
};

module.exports = connectDb;

Dockerfile

 FROM node:latest

 RUN mkdir -p /app
 WORKDIR /app
 #/usr/src/app
 COPY package.json /app
 RUN npm install

 COPY . /app

 EXPOSE 7500

#  ENTRYPOINT ["node"]

 CMD ["node", "src/index.js"]

docker-compose.yml

version: "3"
services:
        deposit:
            container_name: deposit
            image: test/deposit
            restart: always
            build: .
            network_mode: host
            ports:
              - "7500:7500"
            depends_on:
              - mongo
        mongo:
              container_name: mongo
              image: mongo
              volumes:
                - /data:/data/db
              network_mode: host
              ports:
                - '27017:27017'

【问题讨论】:

  • 当您尝试从 js 应用程序连接时,mongo db 可能尚未准备好接受连接。我建议你实现一个重试连接机制。 More.

标签: node.js mongodb docker mongoose


【解决方案1】:

正如评论中提到的,数据库可能还没有准备好接受连接,所以一种方法是添加重试逻辑,或者另一种选择是

serverSelectionTimeoutMS -

使用 useUnifiedTopology,MongoDB 驱动程序将尝试查找服务器 发送任何给定的操作,并继续重试 serverSelectionTimeoutMS 毫秒。如果未设置,则 MongoDB 驱动程序 默认使用 30000(30 秒)。

所以试试下面的选项

const mongoose = require('mongoose');

const uri = 'mongodb://mongo:27017/deposit?retryWrites=true&w=majority';
mongoose.connect(uri, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  serverSelectionTimeoutMS: 50000
}).catch(err => console.log(err.reason));

但是,如果您初始化数据库脚本变得更大,则需要更多时间,因此如果这不起作用,您将使用重试逻辑。在上面的脚本中,它将等待 50 秒。

【讨论】:

  • 我试过了,同样的错误一直显示。我认为甚至在重试逻辑之前就已经存在。但是对我来说似乎不太好的一件事是它只在计算机重新启动后发生,如果我再次执行 docker-compose up,那么它不会显示错误
【解决方案2】:

在您的情况下,节点应用程序在 mongo 准备好之前启动。有两种方法可以解决这个问题:在您的 docker-compose 或您的应用程序中处理它。 您可以使用wait-for-it.sh 或编写wrapper script(均描述为here)以确保您的节点应用程序在数据库准备好后启动。 但是引用自 docker 文档,最好在您的应用程序中处理:

要处理此问题,请将您的应用程序设计为在发生故障后尝试重新建立与数据库的连接。如果应用程序重试连接,它最终可以连接到数据库。

最好的解决方案是在您的应用程序代码中执行此检查, 无论是在启动时还是因任何原因失去连接时

您可以如下实现mongo重试(在this答案中描述):

var connectWithRetry = function() {
  return mongoose.connect(mongoUrl, function(err) {
    if (err) {
      console.error('Failed to connect to mongo on startup - retrying in 5 sec', err);
      setTimeout(connectWithRetry, 5000);
    }
  });
};
connectWithRetry();

【讨论】:

  • 我试过了,错误仍然存​​在。之前的错误是一样的,所以我认为如果 mongo 无法连接,它会自行重试。但是对我来说似乎不太好的一件事是它只在计算机重新启动后发生,如果我再次执行 docker-compose up,那么它不会显示错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
  • 2016-03-02
  • 2018-10-10
  • 1970-01-01
  • 2016-01-29
  • 2022-01-11
相关资源
最近更新 更多