drew kroft
drew kroft

Reputation: 916

sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query')

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

Answers (3)

Fizban
Fizban

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

Srmsbrmnm
Srmsbrmnm

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

stamaimer
stamaimer

Reputation: 6475

You can set SQLALCHEMY_POOL_RECYCLE to a value less than SQLALCHEMY_POOL_TIMEOUT in configuration of Flask-SQLAlchemy. Check the timeouts part of the documentation.

Upvotes: 4

Related Questions