webentwicklung-frage-antwort-db.com.de

Wie man MySQL-Verbindungen in Sqlalchemy richtig schließt?

Ich möchte wissen, was ist richtig Weg, um alle MySQL-Verbindungen in sqlalchemy zu schließen. Für den Kontext handelt es sich um eine Flask-Anwendung, und alle Ansichten verwenden dasselbe session-Objekt.

engine = create_engine("mysql+pymysql://root:[email protected]/my_database")

make_session = sessionmaker(bind=engine, autocommit=False)

session = ScopedSession(make_session)()

Und wenn die App heruntergefahren wird, wird die session geschlossen und die engine entsorgt

session.close()
engine.dispose()

Aber laut Datenbankprotokoll habe ich immer noch viele Fehler wie [Warning] Aborted connection 940 to db: 'master' user: 'root' Host: '172.19.0.7' (Got an error reading communication packets).

Ich habe einige Lösungen ausprobiert, darunter das Aufrufen von gc.collect() und engine.pool.dispose(), aber ohne Erfolg ...

Ich vermute, dass der Motor hinter den Kulissen noch einige Verbindungen geöffnet hat und diese geschlossen werden müssen. Gibt es überhaupt eine Liste aller Sitzungen/Verbindungen, die von der Engine geöffnet wurden?

Nachdem Sie viel Zeit damit verbracht haben, werden alle Ratschläge/Hilfe/Hinweise sehr geschätzt! Vielen Dank.

PS: Die dispose- und close-Aufrufe sind inspiriert von So schließen Sie die sqlalchemy-Verbindung in MySQL . Übrigens, was ist eine ausgecheckte Verbindung?

9
Son

Endlich habe ich den Täter gefunden: Der apscheduler , der im Hintergrund gestartet wird, verwendet eine session, die mit der Datenbank verbunden ist, und scheint sie nicht richtig freizugeben.

Es hat sich auch als bewährte Methode für die Verarbeitung von SQLalchemy-Sitzungen in einer Flask-App erwiesen, scoped_session zu verwenden und am Ende der Anforderung remove() aufzurufen (d. H. appcontext_teardown). Dies wird auch in flask-sqlalchemy extension verwendet.

0
Son

Dies beantwortet Ihre Frage möglicherweise nicht vollständig, aber ich habe diese Methode verwendet, um sicherzustellen, dass alle meine Sitzungen geschlossen sind. Jede Funktion, die eine Sitzung verwendet, erhält den Dekorator provision_session. Beachten Sie, dass das Argument session=None vorhanden sein muss.

z.B

@provide_session()
def my_func(session=None):
    do some stuff
    session.commit()

Ich habe es im Incubator-Airflow-Projekt gesehen und es hat mir sehr gut gefallen.

import contextlib
from functools import wraps

...
Session = ScopedSession(make_session)

@contextlib.contextmanager
def create_session():
    """
    Contextmanager that will create and teardown a session.
    """
    session = Session()
    try:
        yield session
        session.expunge_all()
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()


def provide_session(func):
    """
    Function decorator that provides a session if it isn't provided.
    If you want to reuse a session or run the function as part of a
    database transaction, you pass it to the function, if not this wrapper
    will create one and close it for you.
    """
    @wraps(func)
    def wrapper(*args, **kwargs):
        arg_session = 'session'

        func_params = func.__code__.co_varnames
        session_in_args = arg_session in func_params and \
            func_params.index(arg_session) < len(args)
        session_in_kwargs = arg_session in kwargs

        if session_in_kwargs or session_in_args:
            return func(*args, **kwargs)
        else:
            with create_session() as session:
                kwargs[arg_session] = session
                return func(*args, **kwargs)

    return wrapper
6
Sebastian