2014-12-03 2 views
6

Ich habe eine Flask-Webanwendung, die SQLAlchemy verwendet, um auf eine PostgreSQL-Datenbank zuzugreifen.Flask und SQLAlchemy verursacht eine Menge IDLE in Transaktionsverbindungen in PostgreSQL

Wenn ich die Anwendung starte, wird sofort eine "in transaction" Verbindung in PostgreSQL erstellt.

Wenn die Anwendung eine Zeitlang verwendet wurde, werden mehrere dieser Verbindungen in pg_stat_activity angezeigt.

Nach einiger Zeit scheint es, dass Deadlocks auf einigen Ressourcen auftritt, und ich muss die Anwendung neu starten, um es wieder funktionsfähig zu bekommen.

Ich habe gelesen, dass dies passieren kann, wenn ich von einer Sichtfunktion zurückkomme, die Datenbank vor dem Schließen der Db-Sitzung verwendet. Also, um dieses Problem zu vermeiden, habe ich die folgenden Dekorateur erstellt:

@app.teardown_appcontext 
def shotdown_session(exception=None): 
    db.session.remove() 

Dies sollte dazu führen, alle Sitzungen nach jeder Anfrage geschlossen werden und effektiv das Problem, „in der Transaktion“ Verbindungen zu vermeiden.

Leider scheint es keine Wirkung zu haben.

Also, wie kann ich dieses Problem wirklich lösen?

UPDATE:

sollte ich wohl hinzufügen, dass ich, dass meine Dekorateur Funktion überprüft haben, tatsächlich ausgeführt werden. Ich überprüfte diese durch einen Druck auf sie und fügte hinzu:

@app.teardown_appcontext 
def shotdown_session(exception=None): 
    print "@app.teardown_appcontext: shotdown_session()" 
    db.session.remove() 

Ich habe auch festgestellt, dass es in der Tat nach der Rückkehr der View-Funktion durch Hinzufügen eines Druck auf die View-Funktion auch ausgeführt wird:

[...] 
products = db.session.query(...).all() 
print "BEFORE RETURN" 
return render_template("show_products.html", products=products) 

Dies erzeugt Protokollzeilen wie diese:

* Running on http://0.0.0.0:5000/ 
* Restarting with reloader 
BEFORE RETURN 
@app.teardown_appcontext: shotdown_session() 
10.0.0.100 - - [03/Dec/2014 13:41:30] "GET /product/51 HTTP/1.1" 200 - 

ich vor jeder Rückkehr eine db.session.remove() -Aufruf auch den Code ging durch und fügte in jeder Funktion db.session mit . Dies wird die in der Transaktion loswerden, aber es verursacht auch Probleme. Ich übergebe SQLAlchemy-Modellobjekte aus der Datenbank an die Vorlagen. Einige Vorlagen führen dann einige Operationen an diesen Modellobjekten durch, die dazu führen, dass die Anwendung fehlschlägt, da das Objekt nicht mehr an eine Sitzung gebunden ist.

EDIT 2014.12.08:

Verbindung einrichten kann hier gesehen werden:

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker, scoped_session 
from flask_sqlalchemy import SQLAlchemy 

from config import cfg 

engine = create_engine(cfg["db_uri"], echo=False, pool_size=10) 
db = SQLAlchemy() 
Base = db.Model 
Session = scoped_session(sessionmaker(bind=engine)) 

Die Struktur der gesamten Anwendung kann hier gefunden werden: http://paste.yt/p3219.html

+0

Wie sieht Ihre sqlalchemy Engine oder der Verbindungscode aus? Machst du irgendetwas mit Autocommit oder anderen Optionen? – aezell

+0

Ich habe oben die SQL Engine-Konfiguration hinzugefügt. Ich habe auch Auszüge aus relevanten Dateien hinzugefügt, um die gesamte Struktur der Anwendung zu zeigen. Wenn Sie irgendwelche allgemeinen Inputs oder Verbesserungen zu meiner Arbeit haben, lassen Sie es mich wissen :) – Thomas

+0

Verwenden Sie ein Pooling für Postgres selbst, wie zum Beispiel pgbouncer oder so? Die Kombination solcher Tools mit dem SQLAlchemy-Pooling kann zu ungewöhnlichen Verbindungsproblemen führen. – aezell

Antwort

3

I‘ Diese Situation tritt auf, wenn Sie Flask in Debug mode ausführen. Wenn Ihr Code eine Ausnahme auslöst und der Debugger startet, wird die Transaktion niemals "zurückgesetzt" oder "entfernt". Daher wird die Sitzung, die für die fehlgeschlagene Anforderung verwendet wurde, nie an den Pool zurückgegeben.

Die Lösung ist Debug-Modus zu deaktivieren.

+0

Ich bekomme dies sowohl im Debug- als auch im Nicht-Debug-Modus. – Thomas

+0

Haben Sie versucht, das neueste Flask-SQLAlchemy-Modul zu verwenden? Sieht so aus, als ob du eine ältere Version benutzt. Schau dir diesen Punkt im Code an, um zu sehen, was er automatisch für dich tut: https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy/__init__.py#L807 –

+0

Ich werde das versuchen und zurück – Thomas

Verwandte Themen