如何使用insert_many方法处理pymongo AutoReconnect异常

时间:2017-06-09 06:17:45

标签: mongodb pymongo bulkinsert replicaset

我有一个包含3个成员的MongoDB副本集和一个存储数据的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方法。根据{{​​3}},批量写入不是原子的,因此即使发生其中一个异常,也可能已经有一些文档成功写入数据库。因此,我不能简单地重复使用上面的包装器方法。

如何处理这些情况的最佳方法是什么?

1 个答案:

答案 0 :(得分:3)

对于这种情况, BulkWriteError 必须提供已完成内容的详细信息 https://api.mongodb.com/python/current/examples/bulk.html#ordered-bulk-write-operations

但是如果发生连接丢失,则会发送 AutoReconnect ,并且有关操作进度的信息似乎丢失(针对pymongo进行测试== 3.5.1)

在任何情况下,您都需要重建已写入的内容以及未编写的内容,然后重试剩余项目的操作。 在后一种情况下,由于您没有事先了解实际编写的内容但仍然可行,因此有点困难

作为草图解决方案: 除非 _id 已存在,否则要为每个要插入的文档分配 ObjectId 。您可以自己处理 - 迭代文档,为缺少文档的人手动分配 _id ,并将ID保存在临时变量中。一旦你遇到异常,找到最后的 _id 成功插入利用,即类似于二进制搜索的方法,在最坏的~O(logN)查询,并且也可以使用事实批量操作分成更小的批次(https://api.mongodb.com/python/current/examples/bulk.html#bulk-insert)。但是,这种方法的适用性取决于您在mongod实例上的负载配置文件以及是否可以接受其他查询突发。如果按预期抛出 BulkWriteError ,您只需抓取未插入的文档,然后仅重试这些文档的操作。

回到自动重新连接问题,我个人在 mongo-python-driver 问题跟踪器中打开一张票,很可能是一个bug或者是像那样有目的地完成