【问题标题】:How to handle pymongo AutoReconnect exception with insert_many method如何使用 insert_many 方法处理 pymongo AutoReconnect 异常
【发布时间】:2017-06-09 06:17:44
【问题描述】:

我有一个包含 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 方法。根据documentation 的说法,批量写入不是原子的,因此即使发生其中一种异常,也可能已经有一些文档成功写入数据库。因此,我不能像上面那样简单地重用包装器方法。

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

【问题讨论】:

  • 您提供的代码与我在问题中发布的代码基本相同。我的用例不同,涉及不能简单重试的批量操作,因为部分文档已经可以写入数据库。

标签: mongodb pymongo bulkinsert replicaset


【解决方案1】:

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

但是在连接丢失的情况下,AutoReconnect 被发送,并且操作进度的信息似乎丢失了(针对 pymongo==3.5.1 进行了测试)

在任何情况下,您都需要重建已写入的内容和未写入的内容,然后重试剩余项目的操作。 在后一种情况下,这会有点困难,因为您没有关于实际编写但仍然可行的事先信息

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

回到 AutoReconnect 问题,我会亲自在 mongo-python-driver 问题跟踪器中开一张票,很有可能它是一个错误或正在完成故意的

【讨论】:

  • 我检查了所有这些,但这就是问题所在,如果抛出AutoReconnect,它缺少关于到目前为止所做的事情的信息。您能否详细说明如何重构已写入的内容?因为它不是那么容易,考虑到写入可能来自多个位置,并且项目可以具有相同的语义键(不重复)。
  • 增强了我的回答
  • 开票可能是一个很好的方向,至少要找出这样做是否有技术原因。
猜你喜欢
  • 2016-11-16
  • 2017-02-11
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多