2015-01-29 6 views
7

Nach http://docs.sqlalchemy.org/en/rel_0_9/core/pooling.html#disconnect-handling-pessimistic kann SQLAlchemy instrumentiert werden wieder zu verbinden, wenn ein Eintrag im Verbindungspool nicht mehr gültig ist. Ich erstellen Sie den folgenden Testfall dies zu testen:Wie kann SQLAlchemy gelernt werden, sich von einer Unterbrechung zu erholen?

import subprocess 
from sqlalchemy import create_engine, event 
from sqlalchemy import exc 
from sqlalchemy.pool import Pool 

@event.listens_for(Pool, "checkout") 
def ping_connection(dbapi_connection, connection_record, connection_proxy): 
    cursor = dbapi_connection.cursor() 
    try: 
     print "pinging server" 
     cursor.execute("SELECT 1") 
    except: 
     print "raising disconnect error" 
     raise exc.DisconnectionError() 
    cursor.close() 

engine = create_engine('postgresql://[email protected]/test') 

connection = engine.connect() 

subprocess.check_call(['psql', str(engine.url), '-c', 
    "select pg_terminate_backend(pid) from pg_stat_activity " + 
    "where pid <> pg_backend_pid() " + 
    "and datname='%s';" % engine.url.database], 
    stdout=subprocess.PIPE) 

result = connection.execute("select 'OK'") 
for row in result: 
    print "Success!", " ".join(row) 

Aber statt erholt Ich erhalte diese Ausnahme:

sqlalchemy.exc.OperationalError: (OperationalError) terminating connection due to administrator command 
server closed the connection unexpectedly 
     This probably means the server terminated abnormally 
     before or while processing the request. 

Da „Pingen Server“ auf dem Terminal ausgedruckt wird es sicher scheint zu dem Schluss, dass die Ereignis-Listener ist angehängt. Wie kann SQLAlchemy lernen, sich von einer Unterbrechung zu erholen?

Antwort

4

Es sieht aus wie die checkout Methode ist nur aufgerufen, wenn Sie zuerst eine Verbindung aus dem Pool bekommen (zB Ihre connection = engine.connect() Linie)

Wenn Sie anschließend Ihre Verbindung verlieren, müssen Sie explizit, sie ersetzen, so Sie könnten nur eine neue greifen, und wiederholen Sie Ihre sQL:

try: 
    result = connection.execute("select 'OK'") 
except sqlalchemy.exc.OperationalError: # may need more exceptions here 
    connection = engine.connect() # grab a new connection 
    result = connection.execute("select 'OK'") # and retry 

Dies ist ein Schmerz um jedes Bit sQL zu tun wäre, so dass Sie Datenbankabfragen mit so etwas wie wickeln könnte:

def db_execute(conn, query): 
    try: 
     result = conn.execute(query) 
    except sqlalchemy.exc.OperationalError: # may need more exceptions here (or trap all) 
     conn = engine.connect() # replace your connection 
     result = conn.execute(query) # and retry 
    return result 

Die folgende:

result = db_execute(connection, "select 'OK'") 

jetzt gelingen sollte.

Eine andere Möglichkeit wäre auch für die invalidate Methode zu hören, und zu dieser Zeit einige Maßnahmen zu ergreifen, um Ihre Verbindung zu ersetzen.

+2

Sie scheinen zu bestätigen, dass die SQLAlchemy Dokumentation irreführend ist. Der _Pool_ in diesem Kontext ohne Wert, wenn jede Abfrage in eine Hilfsmethode eingebunden werden muss, führt die Ausnahmebehandlung und die explizite Wiederherstellung durch. – eradman