pymongo + flask + gunicorn:“connect=False”時第一次操作前“Authentication failed”
我正在使用 MongoDB Atlas。我有這個 URL 用於連接:
mongodb+srv://<LOGIN>:<PASSWORD>@<URL>/<DB>?retryWrites=true&w=majority&authSource=admin
。我正在使用這個堆棧:flask、gunicorn、pymongo、mongoengine(我不認為它是相關的,因為 mongoengine 實際上使用 pymongo)。
獨角獸配置:
- 同步工作者,
- 執行緒 = 1,
- 工人數 = 8
連接時,我正在使用,
connect=False
因為 pymongo 本身不是分叉安全的。connect=False
它將在第一次操作之前連接到數據庫。它需要設置為False
,因為 gunicorn 使用 pre-fork 模型。但我面臨以下情況:
- 在第一次請求(端點進行一些數據庫操作)時,我收到此錯誤:
pymongo.errors.OperationFailure: Authentication failed., full error: {'ok': 0, 'errmsg': 'Authentication failed.', 'code': 8000, 'codeName': 'AtlasError'}
- 在第二次請求時,一切都很好(即,數據庫操作已成功完成)。
- 如果你按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
.我接受了兩名工人的測試。看起來會出現這種情況:
- 假設我有兩個具有以下 pid 的 gunicorn 同步工作者:22429 和 22430。
- 我收到請求。工人 22429 處理它。一切都很好,因為它是第一個工作人員,看起來它成功地建立了數據庫連接。
- 我按 F5,工人 22429 再次處理它,一切都很好。
- 我再次按 F5,現在工人 22430 處理它。它會引發錯誤“身份驗證失敗”。
- 我再次按 F5,工人 22430 處理它。現在一切都很好,因為那個工人已經建立了聯繫。
- 現在,我所有的工人(我只有兩個)都連接到數據庫。無論我按 F5 多少次,每個請求都會成功完成。
但為什麼它發生在第一次請求上?來自 pymongo:“如果 connect=False,則在第一次操作時連接。”。如果我理解正確,pymongo 應該在實際第一次操作之前連接,成功完成連接,然後才執行該操作。
那為什麼我的第一個數據庫操作對每個工人都失敗了?我應該如何處理這個?
實際上,問題出在 Mongoengine,而不是 PyMongo。在 Mongoengine GitHub 上,我沒有找到與此問題相關的任何內容。我用 Mongoengine 嘗試了很多方法來解決這個問題,但沒有任何效果。唯一的解決方案是拒絕 Mongoengine 並僅使用 PyMongo。
我重寫了我的項目以僅使用 PyMongo。幸運的是,這只是項目的開始,所以並沒有花太多時間。重寫後,一切都按預期工作,配置完全相同。
與此問題無關:
對於那些考慮使用 Mongoengine 或 PyMongo 的人。使用 PyMongo。直接使用 PyMongo 要容易得多,因為它實現了實際的 MongoDB 文件。Mongoengine 改變了一些概念,最終很難閱讀官方 MongoDB 文件和 Mongoengine 文件,後者以不同的方式實現了 MongoDB 文件中的一些概念。是的,通過拒絕更多的抽象,您將避免像我的問題這樣的問題。