pymongo + flask + gunicorn:"Authentication failed" 第一次操作前 "connect=False"

pymongo + flask + gunicorn: "Authentication failed" before first operation when "connect=False"

我正在使用 MongoDB Atlas。我有这个 URL 用于连接:mongodb+srv://<LOGIN>:<PASSWORD>@<URL>/<DB>?retryWrites=true&w=majority&authSource=admin.

我正在使用这个堆栈:flask、gunicorn、pymongo、mongoengine(我不认为它们是相关的,因为 mongoengine 实际上使用 pymongo)。

gunicorn 配置:

连接时,我使用 connect=False 因为 pymongo 本身不是分叉安全的。使用 connect=False 它将在第一次操作之前连接到数据库。需要设置为False,因为gunicorn使用的是pre-fork模型

但是我遇到了以下情况:

  1. 在第一次请求时(端点进行一些数据库操作)我收到此错误:pymongo.errors.OperationFailure: Authentication failed., full error: {'ok': 0, 'errmsg': 'Authentication failed.', 'code': 8000, 'codeName': 'AtlasError'}
  2. 在第二次请求时一切正常(即,数据库操作已成功完成)。
  3. 如果多次按F5,有时会出现“验证失败”的错误,有时又会没事。

如果我设置 connect=True,一切都会好起来的。我从未见过这种“身份验证失败”错误。

但后来我收到这条警告消息:UserWarning: MongoClient opened before fork. Create MongoClient only after forking. See PyMongo's documentation for details: https://pymongo.readthedocs.io/en/stable/faq.html#is-pymongo-fork-safe

所以,显然,connect需要设置为False

我测试了两个工人。看起来会出现这种情况:

  1. 假设我有两个具有以下 pid 的 gunicorn 同步工作者:22429 和 22430。
  2. 我正在收到请求。工人 22429 处理它。一切都很好,因为它是第一个工作人员,看起来它成功建立了数据库连接。
  3. 我正在按F5,工人22429再次处理,一切正常。
  4. 我又按了F5,现在由worker 22430处理。它抛出错误“身份验证失败。”
  5. 我又按F5了,工人22430处理。现在一切都很好,因为那个工作人员已经建立了连接。
  6. 现在,我所有的工人(我只有两个)都连接到了数据库。不管我按多少次 F5,每个请求都会成功完成。

但为什么它会在第一次请求时发生?来自 pymongo:“如果 connect=False,则在第一次操作时连接。”。如果我理解正确,pymongo 应该在实际第一次操作之前连接,成功完成连接,然后才执行该操作。

那为什么我的第一个数据库操作对每个工人都失败了?我该如何处理?

实际上,问题出在 Mongoengine,而不是 PyMongo。在 Mongoengine GitHub 上,我没有找到与此问题相关的任何内容。我用 Mongoengine 尝试了很多方法来解决这个问题,但没有任何效果。唯一的解决方案是拒绝 Mongoengine 并仅使用 PyMongo。

我重写了我的项目以仅使用 PyMongo。幸运的是,这只是项目的开始,所以并没有花费太多时间。重写后一切都按预期使用完全相同的配置工作。

与此问题无关:

对于那些考虑使用 Mongoengine 或 PyMongo 的人。使用 PyMongo。直接使用 PyMongo 更容易,因为它实现了实际的 MongoDB 文档。 Mongoengine 改变了一些概念,最终很难同时阅读官方 MongoDB 文档和 Mongoengine 文档,它们以不同的方式实现了 MongoDB 文档中的一些概念。是的,通过拒绝再进行一种抽象,您将避免像我的问题这样的问题。