0

I am working on a Flask application with a MongoDB database.

I am using that database for my core application data as well as for Flask-Dance token storage (https://flask-dance.readthedocs.io/en/latest/storages.html). The code for the custom storage backend is in token_storages.py, below.

Everything is working perfectly in the Flask development server, but when I try running my prod server via uWSGI I get this error:

UserWarning: MongoClient opened before f
ork. Create MongoClient only after forking. See PyMongo's documentation for details: https://pymongo.readthedocs.io/en/stable/faq.html#is-
pymongo-fork-safeUserWarning: MongoClient opened before f
ork. Create MongoClient only after forking. See PyMongo's documentation for details: https://pymongo.readthedocs.io/en/stable/faq.html#is-
pymongo-fork-safe

All the research I have seen refers to setting connect=False when instantiating PyMongo, but this is having no effect. Per the docs, this setting should be default regardless (https://flask-pymongo.readthedocs.io/en/latest/).

The error doesn't actually show me on what line things are going wrong -- any guidance on how to find what it PyMongo regards as errant would be much appreciated.

All the database calls that I can find are made within the Flask routes, which I believe should work fine (see the example from storyboard_routes.py below.

I believe the below code should be enough to provide details on the app construction but please let me know if anything else should be included.

Finally I did find that setting lazy-apps = true in my uWSGI settings does work around this issue (in wsgi.ini) but I would rather solve the root issue if possible.

Thanks in advance!

This was suggested, but at least today it is inaccurate as connect=true is not the current default. I tried it nevertheless without success. MongoClient opened before fork. Create MongoClient only Flask

Related Versions

Python 3.8.10 pymongo 3.12.0 Flask-PyMongo 2.3.0
 Flask 2.0.1 
Flask-Dance 5.0.0


my_app/init.py

from flask import Flask
from flask_session import Session  # https://pythonhosted.org/Flask-Session
from . import app_config
from .util import misc
from .routes import graph_auth_routes
from .routes import google_auth_routes
from .routes import storyboard_routes
from .db import init_db

def create_app():
    app = Flask(__name__)
    app.config.from_object(app_config)
    azure_oauth = misc.create_azure_dance_blueprint(app)
    google_oauth = misc.create_google_dance_blueprint(app)
    app.config['MONGO_CONNECT'] = False # This has no effect since already the default

    init_db(app)
    Session(app)
    app.register_blueprint(graph_auth_routes.bp)
    app.register_blueprint(google_auth_routes.bp)
    app.register_blueprint(storyboard_routes.bp)
    return app

app=create_app()

my_app/db.py

from flask_pymongo import PyMongo

mongo = PyMongo()

def init_db(app):
    print("Initializing DB")
    mongo.init_app(app)
    return app

my_app/util/token_storages.py

from flask import session
from flask_dance.consumer.storage import BaseStorage
from ..db import mongo


class MongoStorage(BaseStorage):
    def __init__(self, oauth_provider):
        self.oauth_provider = oauth_provider

    def get(self, blueprint):
        print("getting token")
        try:
            token = mongo.db["tokens"].find_one(
                {
                    "contact_id": session["contact_id"],
                    "oauth_provider": self.oauth_provider,
                }
            )["oauth"]["token"]
            return token
        except:
            print("can't find token for %s" % self.oauth_provider)
            return None

    def set(self, blueprint, token):
        print("setting token")
        query = mongo.db["tokens"].update_one(
            {
                "contact_id": session["contact_id"],
                "oauth_provider": self.oauth_provider,
            },
            {"$set": {"oauth.token": token, "oauth_provider": self.oauth_provider}},
            upsert=True,
        )

    def delete(self, blueprint):
        print("deleting token")
        mongo.db["tokens"].delete_one(
            {
                "contact_id": session["contact_id"],
                "oauth_provider": self.oauth_provider,
            }
        )
        return None

my_pp/routes/storyboard_routes.py

@bp.route("/page2_365")
@misc.default_error_handler
def page2_365():
    # Update if Google integration was performed
    if request.args.get("gc_integration"):
        filter = {"_id": session["contact_id"]}
        new_value = {
            "$set": {"gc_integration": misc.str2bool(request.args["gc_integration"])}
        }
        mongo.db["contacts"].update_one(filter, new_value)

wsgi.ini

[uwsgi]
module = lead_wizard:app
master = true
processes = 5
workers=1
socket = /tmp/lead_wizard.sock
chmod-socket = 666
vacuum = true
die-on-term = true
Joenarr Bronarsson
  • 515
  • 2
  • 5
  • 20
  • Does this answer your question? [MongoClient opened before fork. Create MongoClient only Flask](https://stackoverflow.com/questions/51139089/mongoclient-opened-before-fork-create-mongoclient-only-flask) – Michael Ruth Oct 06 '21 at 02:47
  • Nope, that answer asserts that connect=True is the default, which at least today is no longer the case (see the docs linked). Nonetheless I tried that solution without luck. – Joenarr Bronarsson Oct 06 '21 at 03:06

0 Answers0