python - create - ¿Cómo verifica si el cliente para una instancia de MongoDB es válido?
python mongodb collection (4)
En particular, actualmente estoy tratando de verificar si una conexión a un cliente es válida usando la siguiente función:
def mongodb_connect(client_uri):
try:
return pymongo.MongoClient(client_uri)
except pymongo.errors.ConnectionFailure:
print "Failed to connect to server {}".format(client_uri)
Entonces uso esta función como esta:
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
¿Hay una manera de atrapar y lanzar una excepción en la última línea si se da un URI no válido? Inicialmente pensé que para eso era el ConnectionFailure (por lo que podría detectarse al conectarse) pero estaba equivocado.
Si ejecuto el programa con un URI no válido, que no puede ejecutarse, emitir un rendimiento KeyboardInterrupt:
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)
El parámetro de la palabra clave serverSelectionTimeoutMS
de pymongo.mongo_client.MongoClient
controla cuánto tiempo intentará conectarse el controlador a un servidor. El valor predeterminado es 30s.
Establézcalo en un valor muy bajo compatible con su tiempo de conexión típico typical para informar inmediatamente de un error. Debe consultar el DB después de eso para desencadenar un intento de conexión:
>>> maxSevSelDelay = 1 # Assume 1ms maximum server selection delay
>>> client = pymongo.MongoClient("someInvalidURIOrNonExistantHost",
serverSelectionTimeoutMS=maxSevSelDelay)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> client.server_info()
Esto elevará pymongo.errors.ServerSelectionTimeoutError
.
¹ Aparentemente, configurar serverSelectionTimeoutMS
en 0
podría funcionar incluso en el caso particular de que su servidor tenga una latencia muy baja (caso de un servidor "local" con una carga muy ligera, por ejemplo)
Depende de usted capturar esa excepción y manejarla adecuadamente. Algo así :
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)
mostrará:
No servers found yet
Hola, para saber si la conexión está establecida o no, puedes hacer eso:
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")
serverSelectionTimeoutMS
no funciona para mí (Python 2.7.12, MongoDB 3.6.1, pymongo 3.6.0). A. Jesse Jiryu Davis sugirió en un problema de GitHub que primero intentemos una conexión a nivel de socket como una prueba de fuego. Esto hace el truco para mí.
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.
Hay muchos problemas que esto no detectará, pero si el servidor no se está ejecutando o no está disponible, se lo mostraremos de inmediato.
serverSelectionTimeoutMS
Esto define cuánto tiempo se debe bloquear la selección del servidor antes de lanzar una excepción. El valor predeterminado es 30,000 (milisegundos). DEBE ser configurable a nivel de cliente. NO DEBE ser configurable al nivel de un objeto de base de datos, objeto de colección, o al nivel de una consulta individual.
Se eligió este valor predeterminado para que sea suficiente para que se complete una elección primaria del servidor típico. A medida que el servidor mejora la velocidad de las elecciones, este número puede ser revisado a la baja.
Los usuarios que pueden tolerar largos retrasos para la selección del servidor cuando la topología está en flujo pueden establecer esto más alto. Los usuarios que desean "fallar rápido" cuando la topología está en flujo pueden establecer esto en un número pequeño.
Un serverSelectionTimeoutMS de cero PUEDE tener un significado especial en algunos controladores; El significado de cero no está definido en esta especificación, pero todos los controladores DEBEN documentar el significado de cero.
# 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