14

我有一个 bash shell 脚本,它在尝试mongorestore.

我想确保不仅 MongoDB 已启动,而且在我尝试恢复之前它也已准备好接受连接。

现在,我看到的是,mongo 进程已经启动,但是在它准备好接受连接之前进行初始设置(设置日志文件等)需要 45 秒以上。理想情况下,我想继续循环测试连接,并且只有当我能够连接时,我才想运行mongorestore.

有人可以告诉我如何在 Bash 中执行此操作或为我指明正确的方向吗?

4

6 回答 6

28

要像您建议的那样在循环中测试连接,

until nc -z localhost 27017
do
    sleep 1
done
于 2013-03-15T23:53:27.777 回答
14

使用 MongoDB 工具的解决方案。在 docker 容器或您不想安装的类似容器中很有用nc

until mongo --eval "print(\"waited for connection\")"
  do
    sleep 60
  done

根据其他人的回答。

于 2017-07-12T14:24:00.393 回答
8

我最近遇到了同样的问题。我决定将mongod配置为将其所有输出记录到日志文件中,然后在循环中等待检查​​日志文件,直到我们看到一些表明 mongod 已准备好的输出。

这是我们需要等待的示例日志文件输出行:

Tue Dec  3 14:25:28.217 [initandlisten] waiting for connections on port 27017

这是我想出的 bash 脚本:

#!/bin/bash

# 初始化一个mongo数据文件夹和日志文件
mkdir -p /data/db
触摸 /var/log/mongodb.log

# 使用日志记录启动 mongodb
# --logpath 没有这个 mongod 会将所有日志信息输出到标准输出。
# --logappend 确保 mongod 将新条目附加到日志文件的末尾。我们先创建它,这样下面的尾巴总能找到一些东西
/usr/bin/mongod --quiet --logpath /var/log/mongodb.log --logappend &

# 等到 mongo 记录它准备好(或 60 秒后超时)
计数器=0
grep -q '等待端口连接' /var/log/mongodb.log
而 [[ $? -ne 0 && $COUNTER -lt 60 ]] ; 做
    睡觉 2
    让计数器+=2
    echo "正在等待 mongo 初始化...(到目前为止 $COUNTER 秒)"
    grep -q '等待端口连接' /var/log/mongodb.log
完毕

# 现在我们知道 mongo 已经准备好了,可以继续执行其他命令
...

请注意,脚本不会永远等待,它会在 60 秒后超时 - 根据您的用例,您可能想要也可能不想要。

于 2013-12-03T14:42:56.730 回答
6

在创建用户之前,我需要在 Docker 中运行 Mongo 进行初始化。我结合了 Tom 和 Björn 的答案。这是我正在使用的脚本:

#!/bin/bash

# Wait until Mongo is ready to accept connections, exit if this does not happen within 30 seconds
COUNTER=0
until mongo --host ${MONGO_HOST} --eval "printjson(db.serverStatus())"
do
  sleep 1
  COUNTER=$((COUNTER+1))
  if [[ ${COUNTER} -eq 30 ]]; then
    echo "MongoDB did not initialize within 30 seconds, exiting"
    exit 2
  fi
  echo "Waiting for MongoDB to initialize... ${COUNTER}/30"
done

# Connect to the MongoDB and execute the create users script
mongo ${FWRD_API_DB} /root/create-user.js --host ${MONGO_HOST} -u ${MONGO_ROOT_USER} -p ${MONGO_ROOT_PASSWORD} --authenticationDatabase admin
于 2019-05-22T20:46:04.817 回答
5

虽然汤姆的答案在大多数情况下都可以很好地工作,但如果您使用-e标志运行脚本,它可能会失败。set -e我的意思是你在最上面运行你的脚本。为什么?因为汤姆的回答依赖于上一个命令的退出状态,在这种情况下grep -q如果找不到所需的字符串就会失败,因此整个脚本都会失败。-e标志文档提供了有关如何避免此问题的线索:

如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、if 语句中测试的一部分、在 && 或 || 中执行的任何命令的一部分,则 shell 不会退出 列出除了最后一个 && 或 || 之后的命令,管道中除最后一个之外的任何命令,或者命令的返回状态是否用 ! 反转。

因此,一种解决方案是使 grep 命令成为 while 条件的一部分。但是,由于他使用该选项运行 mongodb,--logappend因此搜索字符串可能会作为先前运行的结果出现。我将其他人的答案与汤姆的答案结合起来,效果非常好:

# Wait until mongo logs that it's ready (or timeout after 60s)
COUNTER=0
while !(nc -z localhost 27017) && [[ $COUNTER -lt 60 ]] ; do
    sleep 2
    let COUNTER+=2
    echo "Waiting for mongo to initialize... ($COUNTER seconds so far)"
done

我发现使用 tomcat 是最好的解决方案,因为它实际上测试是否有东西在听。

于 2017-03-03T12:04:13.507 回答
0

可能的 Docker 解决方案:

鉴于docker_id对我来说,它的工作原理docker logs如下:

until [ $(docker logs --tail all $docker_id | grep "waiting for connections on port" | wc -l) -gt 0 ]; do
    printf '.'
    sleep 1
done

然后继续任何依赖于 mongo 的任务。

于 2019-10-25T09:40:50.813 回答