Reputation: 916
I'm working with Python, Flask, and SQLAlchemy. I've been using a local database while building my application, and it has been working fine with the following code:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config[
'SQLALCHEMY_DATABASE_URI'] = \
'mysql+pymysql://<username>:<password>@localhost/<DBName>'
db = SQLAlchemy(app)
Now, I'm trying to get this code to connect to a remote database using the Python package sshtunnel. Here is what this code looks like:
from flask import Flask
from sshtunnel import SSHTunnelForwarder
from flask_sqlalchemy import SQLAlchemy
forwarding_server = SSHTunnelForwarder(
'1.2.3.4', #my host IP address
ssh_username="user",
ssh_password="password",
remote_bind_address=('127.0.0.1', 8080)
)
forwarding_server.start()
local_port = str(forwarding_server.local_bind_port)
app = Flask(__name__)
app.config[
'SQLALCHEMY_DATABASE_URI'] = \
'mysql+pymysql://<username>:<password>@127.0.0.1:' + local_port + '/<DBName>'
db = SQLAlchemy(app)
It SEEMS like this is connecting, but immediately after launching my flask application, I'm receiving the following error:
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query')
Any insight into this issue would be helpful. Thanks in advance!
Upvotes: 3
Views: 12866
Reputation: 61
When you specify SQLALCHEMY_DATABASE_URI you tell flask_sqlalchemy this is an open session which is being asserted on app_context.
When exiting app_context flask_sqlalchemy is closing active sessions, including your DB session
I don't know your application's flow, but do your best to close DB session before exiting app_context, and be sure you know exactly where a new DB session is being created and used in app_context.
Upvotes: 1
Reputation: 147
I tried pool_recycle value less than wait_timeout (used 50 for mariadb database), but I do not know why it didn't work for me! Using an explicit pre_ping and session rollback / close within a try / except block work for me. I used this decorator below to wrap all my functions and that solved my problem:
def manage_session(f):
def inner(*args, **kwargs):
# MANUAL PRE PING
try:
db.session.execute("SELECT 1;")
db.session.commit()
except:
db.session.rollback()
finally:
db.session.close()
# SESSION COMMIT, ROLLBACK, CLOSE
try:
res = f(*args, **kwargs)
db.session.commit()
return res
except Exception as e:
db.session.rollback()
raise e
# OR return traceback.format_exc()
finally:
db.session.close()
return inner
and then decorated my functions like below:
@manage_session
def my_function(*args, **kwargs):
return "result"
Upvotes: 1