Forums

Internal Server Error - Database connections closed.

Dear all. I am looking for some support here. I am enthusiast coder developing a Python Flask app for my sports group. By no means am I a developer. The app runs mostly successfully by now.

I use SQLAlchemy and connect to the MySQL DB on Pythonanywhere.

app = Flask(__name__)
app.config['SECRET_KEY'] = 'a_very_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqlconnector://USER:PASSWORDv@USER.mysql.eu.pythonanywhere-services.com/DB$DB'
app.config['SQLALCHEMY_POOL_RECYCLE'] = 280
db = SQLAlchemy(app)
migrate = Migrate(app, db)

After a few minutes on first visit to the website (it queries the Database right away) the internal server error is shown. I assume it's because of issues with the database connection timeout.

mysql.connector.errors.OperationalError: MySQL Connection not available.
**NO MATCH**
The above exception was the direct cause of the following exception:
**NO MATCH**
Traceback (most recent call last):
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask/app.py", line 1455, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask/app.py", line 869, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask/app.py", line 867, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask/app.py", line 852, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask_login/utils.py", line 284, in decorated_view
    elif not current_user.is_authenticated:
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/werkzeug/local.py", line 311, in __get__
    obj = instance._get_current_object()
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/werkzeug/local.py", line 515, in _get_current_object
    return get_name(local())
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask_login/utils.py", line 25, in <lambda>
    current_user = LocalProxy(lambda: _get_user())
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask_login/utils.py", line 372, in _get_user
    current_app.login_manager._load_user()
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/flask_login/login_manager.py", line 364, in _load_user
    user = self._user_callback(user_id)
  File "/home/padel/app.py", line 157, in load_user
    return Player.query.get(int(user_id))
  File "<string>", line 2, in get
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/util/deprecations.py", line 386, in warned
    return fn(*args, **kwargs)  # type: ignore[no-any-return]
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/orm/query.py", line 1136, in get
    return self._get_impl(ident, loading.load_on_pk_identity)
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/orm/query.py", line 1145, in _get_impl
    return self.session._get_impl(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 3831, in _get_impl
    return db_load_fn(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/orm/loading.py", line 690, in load_on_pk_identity
    session.execute(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2306, in execute
    return self._execute_internal(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2188, in _execute_internal
    result: Result[Any] = compile_state_cls.orm_execute_statement(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/orm/context.py", line 293, in orm_execute_statement
    result = conn.execute(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1416, in execute
    return meth(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 516, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1639, in _execute_clauseelement
    ret = self._execute_context(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1820, in _execute_context
    self._handle_dbapi_exception(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 2343, in _handle_dbapi_exception
    raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1814, in _execute_context
    context = constructor(
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 1399, in _init_compiled
    self.cursor = self.create_cursor()
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 1723, in create_cursor
    return self.create_default_cursor()
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 1729, in create_default_cursor
    return self._dbapi_connection.cursor()
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 1491, in cursor
    return self.dbapi_connection.cursor(*args, **kwargs)
  File "/home/padel/.virtualenvs/venv/lib/python3.10/site-packages/mysql/connector/connection_cext.py", line 706, in cursor
    raise OperationalError("MySQL Connection not available.")
sqlalchemy.exc.OperationalError: (mysql.connector.errors.OperationalError) MySQL Connection not available.
[SQL: SELECT player.id AS player_id, player.name AS player_name, player.skill_level AS player_skill_level, player.match_id AS player_match_id, player.paid AS player_paid, player.position AS player_position, player.is_admin AS player_is_admin, player.on_waitlist AS player_on_waitlist, player.regular AS player_regular, player.signup_week AS player_signup_week 
FROM player 
WHERE player.id = %(pk_1)s]
[parameters: [{'pk_1': 35}]]

This is the route that I assume causes the error right away:

@app.route('/', methods=['GET', 'POST'])
def index():
    form = SignupForm()

    current_week_number = date.today().isocalendar()[1]

    players_count = len(Player.query.filter_by(signup_week=current_week_number).all())

    courts_config = Configuration.query.filter_by(key="available_courts").first()
    if courts_config:
        max_players = int(courts_config.value) * 4
    else:
        max_players = 0

    is_on_waitlist = players_count >= max_players

    if form.validate_on_submit():
        # Check if a player with the given name exists in the database
        player_in_db = Player.query.filter_by(name=form.name.data).first()

        if player_in_db and player_in_db.regular:
            # If they are a regular, check if they are signed up for the current week
            existing_signup = Player.query.filter_by(name=form.name.data, signup_week=current_week_number).first()
            if existing_signup:
                # If signed up, remove their signup_week and display an opt-out message
                existing_signup.signup_week = None
                db.session.commit()
                flash(f"{form.name.data} has opted out for this week. Thanks! You will be signed up automatically next week", 'danger')
        else:
            # Check if a player with the same name is already signed up for the current week
            existing_player = Player.query.filter_by(name=form.name.data, signup_week=current_week_number).first()
            if existing_player:
                flash(f"{form.name.data} is already signed up for the current week. If it was not you, please add your initial to your name", 'danger')
            else:
                player = Player(name=form.name.data, skill_level=form.skill_level.data, 
                                signup_week=current_week_number, on_waitlist=is_on_waitlist)
                db.session.add(player)
                db.session.commit()
                flash(f"Thank you for signing up, {form.name.data}!", 'success')

        return redirect(url_for('index'))



    return render_template('signup.html', form=form, courts=max_players // 4, 
                           players_count=players_count, max_players=max_players, is_on_waitlist=is_on_waitlist)

What can I do to be sure that the application loads right away when a player visits the site? I assume it's about closing the DB connections once commits have been made but I struggle to wrap my head around the details. Unless it's something else entirely.

Any help or directions are greatly appreciated.

Thanks!

More information. I am running SQLAlchemy 3.1.1 so it seems the correct way to define the pool recycle is

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqlconnector://USER:PASSWORD@padel.mysql.eu.pythonanywhere-services.com/DB$DB'
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'pool_recycle': 280}

I test with this.

Does it work when you use that?

Yes, it does indeed.

Thanks for sharing that!