2015-05-29 11 views
20

In particolare, Attualmente sto cercando di verificare se una connessione a un client è valido utilizzando la seguente funzione:Come si controlla se il client per un'istanza MongoDB è valido?

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

Ho quindi utilizzare questa funzione come questa:

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 

Esiste un modo catturare e lanciare un'eccezione sull'ultima riga se viene fornito un URI non valido? Inizialmente pensavo che fosse a causa di ConnectionFailure (quindi questo potrebbe essere catturato durante la connessione) ma ho sbagliato.

Se eseguo il programma con un URI non validi, che non riesce a funzionare, l'emissione di un KeyboardInterrupt rendimenti:

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) 
+0

pymongo.errors.ConnectionFailure viene generato quando l'host da client_uri non è disponibile ma se il database non esiste nell'host è stato creato, quindi è necessario verificare l'esistenza del db in precedenza. – imarban

+0

Grazie. Come si controlla l'esistenza del db in anticipo? – Leeren

+0

Il metodo database_names nella classe MongoClient potrebbe aiutare. – imarban

risposta

30

Il parametro serverSelectionTimeoutMS parola chiave di pymongo.mongo_client.MongoClient controlla per quanto tempo il driver cercherà di connettersi a un server. Il valore predefinito è 30 secondi.

Impostarlo su un valore molto basso compatibile con il tempo di connessione tipico¹ per segnalare immediatamente un errore. È necessario interrogare il DB dopo che per innescare un tentativo di connessione:

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

Ciò consentirà di aumentare pymongo.errors.ServerSelectionTimeoutError.

¹ Apparentemente impostazione serverSelectionTimeoutMS a 0 potrebbe anche lavorare nel caso particolare il server ha una latenza molto bassa (caso di un server "locale" con carico molto leggero, per esempio)


E ' sta a te prendere nota di questa eccezione e gestirla correttamente. Qualcosa come che:

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) 

visualizzerà:

No servers found yet 
+1

Questo funziona bene. Ho avuto un problema in cui se il serverSelectionTimeoutMS era impostato su 0, avrebbe sempre detto che l'istanza MongoDB era inattiva. Impostandolo su 1 ms è stato risolto questo problema. –

+0

Grazie per avermelo dichiarato @James! Ho aggiornato la risposta di conseguenza. Stai utilizzando un * cluster * di server MongoDB o un * single * server? –

+0

@SylvainLeroux Sto solo usando un singolo server :) –

0

Salve per scoprire che la connessione è stabilita o non si può fare:

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") 
0

serverSelectionTimeoutMS

Definisce per quanto tempo bloccare la selezione del server prima di generare un'eccezione . Il valore predefinito è 30.000 (millisecondi). Deve essere configurabile a livello di client. NON DEVE essere configurabile al livello di un oggetto di database, oggetto di raccolta o al livello di una singola query .

Questo valore predefinito è stato scelto per essere sufficiente per il completamento di un elezione primaria del server tipico . Poiché il server migliora la velocità delle elezioni di , questo numero può essere rivisto al ribasso.

Gli utenti che possono tollerare lunghi ritardi per la selezione del server quando la topologia è in flusso possono impostarla più in alto.Gli utenti che vogliono "fallire velocemente" quando la topologia è in flusso possono impostarlo su un numero piccolo.

Un serverSelectionTimeoutMS di zero PU have avere un significato speciale in alcuni driver ; il significato dello zero non è definito in questa specifica, ma tutti i driver DOVREBBE documentare il significato di 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 
0

serverSelectionTimeoutMS non funziona per me (Python 2.7.12, 3.6.1 MongoDB, pymongo 3.6.0). A. Jesse Jiryu Davis suggerito in a GitHub issue che tentiamo prima una connessione a livello di socket come una cartina di tornasole. Questo è il trucco per 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. 

Ci sono un sacco di problemi di questo non prenderà, ma se il server non è in esecuzione o non è raggiungibile, questo lo mostrerò subito.