Подтвердить что ты не робот

Как вы проверяете, действительно ли клиент для экземпляра MongoDB?

В частности, я пытаюсь проверить, действительно ли соединение с клиентом работает с помощью следующей функции:

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

Затем я использую эту функцию следующим образом:

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

Есть ли способ уловить и выбросить исключение в последней строке, если указан недопустимый URI? Сначала я подумал, для чего был ConnectionFailure (так что это можно было поймать при подключении), но я ошибся.

Если я запускаю программу с недопустимым URI, который не запускается, выдача 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)
4b9b3361

Ответ 1

Параметр ключевого слова serverSelectionTimeoutMS pymongo.mongo_client.MongoClient определяет, как долго драйвер попытается подключиться к серверу. Значение по умолчанию - 30 с.

Установите его на очень низкое значение, совместимое с типичным временем соединения¹, чтобы немедленно сообщить об ошибке. После этого вам нужно запросить БД, чтобы вызвать попытку подключения:

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

Это приведет к повышению pymongo.errors.ServerSelectionTimeoutError.

¹ Очевидно, что установка serverSelectionTimeoutMS - 0 может работать даже в конкретном случае, когда ваш сервер имеет очень низкую задержку (например, "локальный" сервер с очень легкой нагрузкой)


Это зависит от вас, чтобы поймать это исключение и правильно обработать его. Что-то вроде этого:

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)

отобразит:

No servers found yet

Ответ 2

Привет, чтобы узнать, что соединение установлено или нет, вы можете это сделать:

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

Ответ 3

serverSelectionTimeoutMS

Это определяет, как долго блокировать выбор сервера, прежде чем бросать исключение. Значение по умолчанию - 30 000 (миллисекунды). Это должно быть настраивается на уровне клиента. Он НЕ ДОЛЖЕН настраиваться на уровня объекта базы данных, объекта коллекции или уровня индивидуальный запрос.

Это значение по умолчанию было выбрано для типичного сервера первичные выборы для завершения. Поскольку сервер улучшает скорость выборов, это число может быть пересмотрено вниз.

Пользователи, которые могут переносить длительные задержки для выбора сервера, когда топология в потоке может установить это выше. Пользователи, которые хотят "провалиться" fast ", когда топология находится в потоке, может установить это на небольшое число.

СерверSelectionTimeoutMS нуля имеет значение в некоторых случаях водители; нулевое значение не определено в этой спецификации, но все драйверы СЛЕДУЕТ документировать значение нуля.

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

Ответ 4

serverSelectionTimeoutMS не работает для меня (Python 2.7.12, MongoDB 3.6.1, pymongo 3.6.0). A. Jesse Jiryu Davis предложил в вопрос GitHub, что мы сначала пытаемся подключиться к сокету как тест лакмусовой бумажки. Это делает трюк для меня.

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.

Есть много проблем, которые не поймают, но если сервер не запущен или недоступен, это сразу покажет вам.