How do you check if the client for a MongoDB instance is valid?

PythonMongodbPymongo

Python Problem Overview


In particular, I am currently trying to check if a connection to a client is valid using the following function:

def mongodb_connect(client_uri):
    try:
        return pymongo.MongoClient(client_uri)
    except pymongo.errors.ConnectionFailure:
         print "Failed to connect to server {}".format(client_uri)

I then use this function like this:

def bucket_summary(self):
    client_uri = "some_client_uri"
    client = mongodb_connect(client_uri)
    db = client[tenant_id]
    ttb = db.timebucket.count() # If I use an invalid URI it hangs here

Is there a way to catch and throw an exception at the last line if an invalid URI is given? I initially thought that's what the ConnectionFailure was for (so this could be caught when connecting) but I was wrong.

If I run the program with an invalid URI, which fails to run, issuing a KeyboardInterrupt yields:

File "reportjob_status.py", line 58, in <module>
tester.summarize_timebuckets()
File "reportjob_status.py", line 43, in summarize_timebuckets
ttb = db.timebucket.count() #error
File "/Library/Python/2.7/site-packages/pymongo/collection.py", line   1023, in count
return self._count(cmd)
File "/Library/Python/2.7/site-packages/pymongo/collection.py", line 985, in _count
with self._socket_for_reads() as (sock_info, slave_ok):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 17, in __enter__
return self.gen.next()
File "/Library/Python/2.7/site-packages/pymongo/mongo_client.py", line 699, in _socket_for_reads
with self._get_socket(read_preference) as sock_info:
File  "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 17, in __enter__
return self.gen.next()
File "/Library/Python/2.7/site-packages/pymongo/mongo_client.py", line 663, in _get_socket
server = self._get_topology().select_server(selector)
File "/Library/Python/2.7/site-packages/pymongo/topology.py", line 121, in select_server
address))
File "/Library/Python/2.7/site-packages/pymongo/topology.py", line 106, in select_servers
self._condition.wait(common.MIN_HEARTBEAT_INTERVAL)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 358, in wait
_sleep(delay)

Python Solutions


Solution 1 - Python

The serverSelectionTimeoutMS keyword parameter of pymongo.mongo_client.MongoClient controls how long the driver will try to connect to a server. The default value is 30s.

Set it to a very low value compatible with your typical connection time¹ to immediately report an error. You need to query the DB after that to trigger a connection attempt :

>>> maxSevSelDelay = 1 # Assume 1ms maximum server selection delay
>>> client = pymongo.MongoClient("someInvalidURIOrNonExistantHost",
                                 serverSelectionTimeoutMS=maxSevSelDelay)
//                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> client.server_info()

This will raise pymongo.errors.ServerSelectionTimeoutError.

¹ Apparently setting serverSelectionTimeoutMS to 0 might even work in the particular case your server has very low latency (case of a "local" server with very light load for example)


It is up to you to catch that exception and to handle it properly. Something like that:

try:
    client = pymongo.MongoClient("someInvalidURIOrNonExistantHost",
                                     serverSelectionTimeoutMS=maxSevSelDelay)
    client.server_info() # force connection on a request as the
                         # connect=True parameter of MongoClient seems
                         # to be useless here 
except pymongo.errors.ServerSelectionTimeoutError as err:
    # do whatever you need
    print(err)

will display:

No servers found yet

Solution 2 - Python

Hi to find out that the connection is established or not you can do that :

from pymongo import MongoClient
from pymongo.errors import ConnectionFailure
client = MongoClient()
try:
   # The ismaster command is cheap and does not require auth.
   client.admin.command('ismaster')
except ConnectionFailure:
   print("Server not available")

Solution 3 - Python

serverSelectionTimeoutMS

> This defines how long to block for server selection before throwing an > exception. The default is 30,000 (milliseconds). It MUST be > configurable at the client level. It MUST NOT be configurable at the > level of a database object, collection object, or at the level of an > individual query. > > This default value was chosen to be sufficient for a typical server > primary election to complete. As the server improves the speed of > elections, this number may be revised downward. > > Users that can tolerate long delays for server selection when the > topology is in flux can set this higher. Users that want to "fail > fast" when the topology is in flux can set this to a small number. > > A serverSelectionTimeoutMS of zero MAY have special meaning in some > drivers; zero's meaning is not defined in this spec, but all drivers > SHOULD document the meaning of zero.

https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#serverselectiontimeoutms

# pymongo 3.5.1
from pymongo import MongoClient
from pymongo.errors import ServerSelectionTimeoutError

client = MongoClient("mongodb://localhost:27000/", serverSelectionTimeoutMS=10, connectTimeoutMS=20000)

try:
    info = client.server_info() # Forces a call.
except ServerSelectionTimeoutError:
    print("server is down.")

# If connection create a new one with serverSelectionTimeoutMS=30000

Solution 4 - Python

serverSelectionTimeoutMS doesn't work for me (Python 2.7.12, MongoDB 3.6.1, pymongo 3.6.0). A. Jesse Jiryu Davis suggested in a GitHub issue that we attempt a socket-level connection first as a litmus test. This does the trick for me.

def throw_if_mongodb_is_unavailable(host, port):
    import socket
    sock = None
    try:
        sock = socket.create_connection(
            (host, port),
            timeout=1) # one second
    except socket.error as err:
        raise EnvironmentError(
            "Can't connect to MongoDB at {host}:{port} because: {err}"
            .format(**locals()))
    finally:
        if sock is not None:
            sock.close()

# elsewhere...
HOST = 'localhost'
PORT = 27017
throw_if_mongodb_is_unavailable(HOST, PORT)
import pymongo
conn = pymongo.MongoClient(HOST, PORT)
print(conn.admin.command('ismaster'))
# etc.

There are plenty of problems this won't catch, but if the server isn't running or isn't reachable, this'll show you right away.

Solution 5 - Python

Can also be checked this way:

from pymongo import MongoClient
from pymongo.errors import OperationFailure

def check_mongo_connection(client_uri):
    connection = MongoClient(client_uri)

    try:
        connection.database_names()
        print('Data Base Connection Established........')

    except OperationFailure as err:
        print(f"Data Base Connection failed. Error: {err}")

check_mongo_connection(client_uri)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeerenView Question on Stackoverflow
Solution 1 - PythonSylvain LerouxView Answer on Stackoverflow
Solution 2 - PythonManochehr RasouliView Answer on Stackoverflow
Solution 3 - PythonThe DemzView Answer on Stackoverflow
Solution 4 - PythonESVView Answer on Stackoverflow
Solution 5 - Pythonnurealam siddiqView Answer on Stackoverflow