web-dev-qa-db-fra.com

Comment vérifier si le client d'une instance de MongoDB est valide?

En particulier, j'essaie actuellement de vérifier si une connexion à un client est valide en utilisant la fonction suivante:

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

J'utilise ensuite cette fonction comme ceci:

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

Existe-t-il un moyen d'attraper et de lancer une exception à la dernière ligne si un URI non valide est indiqué? Au départ, je pensais que c'était à quoi le ConnectionFailure était destiné (afin que cela puisse être intercepté lors de la connexion), mais j'avais tort.

Si j'exécute le programme avec un URI non valide dont l'exécution a échoué, l'émission d'un KeyboardInterrupt donne:

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)
30
Leeren

Le paramètre de mot clé serverSelectionTimeoutMS de pymongo.mongo_client.MongoClient contrôle la durée pendant laquelle le pilote essaie de se connecter à un serveur. La valeur par défaut est 30s.

Définissez une valeur très faible compatible avec votre temps de connexion typique¹ pour signaler immédiatement une erreur. Vous devez ensuite interroger la base de données pour déclencher une tentative de connexion:

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

Cela augmentera pymongo.errors.ServerSelectionTimeoutError .

¹ Apparemment définir serverSelectionTimeoutMS sur 0 pourrait même fonctionner dans le cas particulier où votre serveur a une latence très faible (cas d'un serveur "local" avec une charge très faible par exemple)


C'est à vous de détecter cette exception et de la gérer correctement. Quelque chose comme ça:

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)

affichera:

No servers found yet
41
Sylvain Leroux

Bonjour pour savoir si la connexion est établie ou non, vous pouvez le faire:

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")
5
Manochehr Rasouli

serverSelectionTimeoutMS ne fonctionne pas pour moi (Python 2.7.12, MongoDB 3.6.1, pymongo 3.6.0). A. Jesse Jiryu Davis suggère dans un problème de GitHub que nous essayions d’abord une connexion au niveau du socket comme test décisif. Cela fait le tour pour moi.

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.

Il y a de nombreux problèmes qui ne seront pas résolus, mais si le serveur n'est pas en cours d'exécution ou n'est pas accessible, cela vous le montrera immédiatement.

1
ESV

serverSelectionTimeoutMS

Ceci définit combien de temps bloquer pour la sélection du serveur avant de lancer un exception. La valeur par défaut est 30 000 (millisecondes). Ce doit être configurable au niveau du client. Il NE DOIT PAS être configurable à la niveau d'un objet de base de données, d'un objet de collection ou au niveau d'un requête individuelle.

Cette valeur par défaut a été choisie suffisante pour un serveur typique élection primaire à compléter. Comme le serveur améliore la vitesse de élections, ce nombre peut être révisé à la baisse.

Utilisateurs pouvant tolérer de longs délais pour la sélection du serveur lorsque le La topologie en mutation peut augmenter ce niveau. Les utilisateurs qui souhaitent "échouer Rapidement" lorsque la topologie est en mutation peuvent définir un petit nombre.

Une valeur serverSelectionTimeoutMS de zéro PEUT avoir une signification spéciale dans certains les chauffeurs; La signification de zéro n'est pas définie dans cette spécification, mais dans tous les pilotes DEVRAIT documenter le sens de zéro.

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

# 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
0
The Demz