Как обрабатывать исключение autoReconnect pymongo с методом insert_many

У меня есть набор реплик MongoDB с 3 членами и приложение Python, которое хранит в нем данные.

Я могу обработать исключение pymongo AutoReconnect при использовании отдельных вставок документов с оберткой следующим образом:

def safe_mongo_call(method, num_retries, *args, **kwargs):
    while True:
        try:
            return method(*args, **kwargs)
        except (pymongo.errors.AutoReconnect,
                pymongo.errors.ServerSelectionTimeoutError) as e:
            if num_retries > 0:
                logger.debug('Retrying MongoDB operation: %s', str(e))
                num_retries -= 1
            else:
                raise

Я не уверен, как справиться с этими исключениями при использовании массовой записи, например. insert_many. Согласно документации объемные записи не являются атомарными, поэтому, даже если происходит одно из исключений, могут быть уже некоторые документы, записанные в базу данных успешно, Таким образом, я не могу просто повторно использовать метод обертки, как указано выше.

Каким образом можно справиться с этими ситуациями?

Ответ 1

В этом случае theres BulkWriteError, который должен предоставить подробную информацию о том, что было сделано https://api.mongodb.com/python/current/examples/bulk.html#ordered-bulk-write-operations

Но в случае потери соединения AutoReconnect отправляется вместо этого, и информация о ходе работы выглядит потерянной (проверена на pymongo == 3.5.1)

В любом случае вам нужно будет восстановить то, что было написано, а что нет, и повторить операцию для остальных элементов. В последнем случае это будет немного сложнее, поскольку у вас нет предварительной информации о том, что было написано, но все же выполнимо

В качестве решения эскиза: каждому документу, который нужно вставить, присваивается ObjectId, если _id уже не присутствует. Вы можете справиться с этим сами - перебирайте документы, вручную назначьте _id для тех, кто его отсутствует, и сохраните идентификаторы во временной переменной. После того, как вы нажмете на исключение, найдите последний _id успешно вставленный рычаг, т.е. Двоичный поисковый подход, чтобы иметь в худшем случае запросы O (logN) и, возможно, также использовать факт, что массовые операции разбиваются на более мелкие партии (https://api.mongodb.com/python/current/examples/bulk.html#bulk-insert). Но, конечно, применимость этого подхода зависит от профиля нагрузки, который у вас есть на ваших экземплярах mongod, и допускаются ли дополнительные запросы всплесков. Если BulkWriteError были выбраны так, как ожидалось, вы можете просто захватить документы, которые не вставлены, и повторить операцию только для этих документов.

Вернемся к проблеме AutoReconnect, я лично открыл билет в трекере проблем с mongo-python-drivers, вероятность того, что он будет либо ошибкой, либо сделаем это специально