Skip to content

Instantly share code, notes, and snippets.

@fschiettecatte
Last active December 10, 2024 23:19
Show Gist options
  • Save fschiettecatte/3a9adef1366cf145344c8f0f1b791451 to your computer and use it in GitHub Desktop.
Save fschiettecatte/3a9adef1366cf145344c8f0f1b791451 to your computer and use it in GitHub Desktop.
Django Connections Errors

Django Connections Errors

For a long time I have been running into problems with Django connection errors when running a database query after a long idle period. This does not affect website per-se because connections last a very short time but for batch processes where there is a long interval between database access, Django does not detect that database has dropped the connection and raises an error.

Which really should not be happening because my database connection settings includes:

    'CONN_MAX_AGE': 3500,                   # 3500 seconds because wait_timeout = 3600 in my.cnf

telling Django that the maximum age of the connection should be 3500 seconds, and the timeout in mysql is set to 3600.

I was hoping that this was going to be fixed with Django 4.2 with this new setting:

    'CONN_HEALTH_CHECKS': True,             # Health check connections

but no change.

I had been dealing with the issue by inserting this before accessing the database:

    connections.close_all()

but this is inelegant.

So I cooked up a decorator and a function to ensure that database connections were all good before database access, here is the function:

from django.db import connections

def ensureDatabaseConnections(reconnect=True):

    # Process all connections
    for _connection in connections.all():

        # The 'is_usable' method only exists if the connection was made
        if _connection.connection and not _connection.is_usable():
            _connection.close()
            if reconnect:
                _connection.connect()

And here is the decorator:

from django.db import connections

def ensureDatabaseConnections(function, reconnect=True):

    # Wrapper
    def wrapper(reconnect=True, **kwargs):

        # Process all connections
        for _connection in connections.all():

            # The 'is_usable' method only exists if the connection was made
            if _connection.connection and not _connection.is_usable():
                _connection.close()
                if reconnect:
                    _connection.connect()

        # Return the wrapped function
        return function(*args, **kwargs)

    # Return the wrapper
    return wrapper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment