I have a bash script which fails. After inspection, it appears that the failure is due to the fact that MongoDB is accessed immediately after being restarted.
For example, running:
mongo --eval "db.version()"
gives the expected output:
MongoDB shell version: 2.4.9
connecting to: test
2.4.9
while running:
service mongodb restart; mongo --eval "db.version()"
produces the following output, emphasis mine:
mongodb stop/waiting
mongodb start/running, process 1466
MongoDB shell version: 2.4.9
connecting to: test
Sat Oct 25 02:52:29.736 Error: couldn't connect to server 127.0.0.1:27017 at src/mongo/shell/mongo.js:145
exception: connect failed
because the server is not ready yet.
What is the correct way to wait during the execution of the bash script until MongoDB is actually ready?
service mongodb status
is not a solution, because it reports the status of the service, and not the database itself.Doing
nc -z localhost 27017
repeatedly until its exit code becomes 0 will work, but I'm not sure if there are no drawbacks (running somehow an infinite loop?)
I have a bash script which fails. After inspection, it appears that the failure is due to the fact that MongoDB is accessed immediately after being restarted.
For example, running:
mongo --eval "db.version()"
gives the expected output:
MongoDB shell version: 2.4.9
connecting to: test
2.4.9
while running:
service mongodb restart; mongo --eval "db.version()"
produces the following output, emphasis mine:
mongodb stop/waiting
mongodb start/running, process 1466
MongoDB shell version: 2.4.9
connecting to: test
Sat Oct 25 02:52:29.736 Error: couldn't connect to server 127.0.0.1:27017 at src/mongo/shell/mongo.js:145
exception: connect failed
because the server is not ready yet.
What is the correct way to wait during the execution of the bash script until MongoDB is actually ready?
service mongodb status
is not a solution, because it reports the status of the service, and not the database itself.Doing
nc -z localhost 27017
repeatedly until its exit code becomes 0 will work, but I'm not sure if there are no drawbacks (running somehow an infinite loop?)
4 Answers
Reset to default 8To start the mongo interpreter without connection to any db:
mongo --nodb
From there, inside the mongo interpreter you can execute:
var conn;
try
{
conn = new Mongo("localhost:27017");
}
catch(Error)
{
//print(Error);
}
while(conn===undefined)
{
try
{
conn = new Mongo("localhost:27017");
}
catch(Error)
{
//print(Error);
}
sleep(100);
}
DB = conn.getDB("test");
Result = DB.runCommand('buildInfo');
print(Result.version);
With the 2 above, you can put the later part in a file like Script.js and then do:
mongo --nodb Script.js
EDIT: There, totally forgot that what you really wanted was the version. Fixed that for you.
Building upon @Magnitus' answer, I've added a timeout and configurable connection string.
var conn;
var interval = 100; // 100 Milliseconds polling
var timeout = 10000; // 10 Seconds timeout
var startTime = new Date();
connectionUrl = connectionUrl.split('/')[2];
if (connectionUrl.indexOf('@') !== -1) {
// Has auth (doesn't need auth for test connection)
connectionUrl = connectionUrl.split('@')[1];
}
while(conn === undefined) {
try {
var elapsed = (new Date() - startTime);
print("Attempting to connect to " + connectionUrl + " elapsed: " + elapsed + "ms");
conn = new Mongo(connectionUrl);
} catch(error) {
print(error);
if ((new Date() - startTime) >= timeout) {
print("ERROR: Failed to establish connection within timeout (" + timeout + "ms)");
quit(1);
} else {
sleep(interval);
}
}
}
print("MongoDB connection established in " + (new Date() - startTime) + "ms");
You can call it like so:
export MONGO_URL="mongo://<user>:<pass>@<host>:<port>/<database>"
mongo --nodb wait_for_mongo.js --eval "connectionUrl=\"$MONGO_URL\""
The script only requires the host:port to test the connection, so MONGO_URL="mongo://localhost"
is enough to test the connection.
Rather than fixing this in the script, a better option (at least for my scenario) is to fix it in the mongo init script / upstart unit / systemd service.
For systemd:
ExecStartPost=/bin/sh -c 'while ! /usr/bin/mongo --eval "db.version()" > /dev/null 2>&1; do sleep 0.1; done'
@Arseni if you want just the verification and minimum message back use quit() and discard the standard error and output messages.
Caveat - you may want to put a timeout - what if mongo does not come up or there is a network issue.
while true
do
mongo --quiet --eval "quit()" 1>/dev/zero 2>&1
rc=$?
if [ $rc -ne 0 ]
then sleep 2
else
break
fi
done