I'm have troubles with SQLalchemy in Flask app first minute after the app start (or restart). It looks like logger exceptions of a sort:
sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (2006, 'MySQL server has gone away') <---- most often one
sqlalchemy.exc.ResourceClosedError: This result object does not return rows. It has been closed automatically.
sqlalchemy.exc.NoSuchColumnError: "Could not locate column in row for column 'users.id'"
sqlalchemy.exc.NoSuchColumnError: "Could not locate column in row for column 'payments.id'"
sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (2013, 'Lost connection to MySQL server during query')
Then everything gets back to normal. It's not a critical issue but annoying.
I tried to run warming up queries upon application start:
with app.app_context():
for _ in range(5):
try:
db.session.execute(statement)
logger.info("DB connection is successfully established")
return
except Exception as e:
logger.warning(e)
time.sleep(1)
raise Exception("Couldn't establish a DB connection")
It passes through just fine but then I see same issues.
It doesn't happen in development environment, only in production where Flask app runs on uwsgi server. Is there a way to fix it?
Update: connection URI looks like this: "mysql+mysqldb://user:password@localhost/mydb?unix_socket=/var/run/mysqld/mysqld.sock"
Seems How to correctly setup Flask + uWSGI + SQLAlchemy to avoid database connection issues worked for them. This is a copy paste of the answer just to avoid "link only answers". I would still recommend anyone arriving at this question to refer the original answer linked above.
The SQLAlchemy manual provides two examples how to approach this: Using Connection Pools with Multiprocessing. The first approach involving Engine.dispose() can be approached using uwsgidecorators.postfork as suggested by Hett - simple example that should work if there's only the default binding involved:
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "postgres:///test"
db.init_app(app)
def _dispose_db_pool():
with app.app_context():
db.engine.dispose()
try:
from uwsgidecorators import postfork
postfork(_dispose_db_pool)
except ImportError:
# Implement fallback when running outside of uwsgi...
raise
return app
Meta: I am posting this as an answer as per OP's comment