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

21

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

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)
    
задан Leeren 29.05.2015 в 23:15
источник
  • pymongo.errors.ConnectionFailure вызывается, когда хост из client_uri недоступен, но если база данных не существует на хосте, она создана, поэтому вам нужно будет проверить существование db раньше. –  imarban 29.05.2015 в 23:32
  • Спасибо. Как вы проверяете существование db заранее? –  Leeren 29.05.2015 в 23:34
  • Метод database_names в классе MongoClient может помочь. –  imarban 29.05.2015 в 23:37

4 ответа

33

Параметр ключевого слова 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
    
ответ дан Sylvain Leroux 29.05.2015 в 23:31
источник
  • Это хорошо работает. У меня возникла проблема: если для serverSelectionTimeoutMS установлено значение 0, всегда будет указано, что экземпляр MongoDB не работает. Установка этого параметра на 1 мс исправила эту проблему. –  James Milner 21.02.2016 в 19:40
  • Спасибо, что указали, что @James! Я соответствующим образом обновил ответ. Вы используете кластер серверов MongoDB или один сервер? –  Sylvain Leroux 23.02.2016 в 11:29
  • @SylvainLeroux Я просто использую один сервер :) –  James Milner 23.02.2016 в 18:09
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")
    
ответ дан Manochehr Rasouli 02.08.2017 в 13:21
источник
1

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.

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

    
ответ дан ESV 12.01.2018 в 23:02
источник
0

serverSelectionTimeoutMS

  

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

     

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

     

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

     

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

Ссылка

# 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
    
ответ дан The Demz 12.10.2017 в 21:32
источник