pymongo + flask + gunicorn:“connect = False”时第一次操作前出现“身份验证失败”

pymongo + flask + gunicorn:“connect = False”时第一次操作前出现“身份验证失败”

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

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

gunicorn配置:

  • 同步工作者,
  • 线程 = 1,
  • 工人数量 = 8

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

但我面临以下情况:

  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. 假设我有两个 gunicorn 同步工作者,其 pid 如下:22429 和 22430。
  2. 我收到了请求。Worker 22429 正在处理它。一切都很好,因为它是第一个 Worker,并且看起来它已成功建立了 DB 连接。
  3. 我按下 F5,工人 22429 再次处理它,一切都正常。
  4. 我再次按下 F5,现在工作人员 22430 正在处理它。它抛出错误“身份验证失败”。
  5. 我再次按下 F5,工作器 22430 处理了这个问题。现在一切都正常了,因为该工作器已经建立了连接。
  6. 现在,我的所有工作人员(只有两个)都已连接到数据库。无论我按 F5 多少次,每个请求都将成功完成。

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

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

答案1

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

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

与此问题无关:

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

相关内容