Frage Wie kann SQLAlchemy lernen, sich von einer Unterbrechung zu erholen?


Gemäß http://docs.sqlalchemy.org/en/rel_0_9/core/pooling.html#disconnect-handling-pessimistic, SQLAlchemy kann instrumentiert werden, um die Verbindung wiederherzustellen, wenn ein Eintrag im Verbindungspool nicht mehr gültig ist. Ich erstelle den folgenden Testfall, um dies zu testen:

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://postgres@localhost/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 anstatt zu erholen, erhalte ich 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 "pinging server" auf dem Terminal gedruckt wird, scheint es sicher zu sein, dass der Event-Listener angeschlossen ist. Wie kann SQLAlchemy lernen, sich von einer Unterbrechung zu erholen?


8
2018-01-29 17:16


Ursprung


Antworten:


Es sieht aus wie die Auschecken Methode ist nur Wenn Sie zum ersten Mal eine Verbindung aus dem Pool erhalten (z. B. Ihre connection = engine.connect() Linie)

Wenn Sie später Ihre Verbindung verlieren, müssen Sie sie explizit ersetzen, so dass Sie einfach eine neue holen und Ihren sql wiederholen können:

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 wäre ein Ärgernis für jedes Bit von SQL, also könnten Sie Datenbankabfragen mit etwas wie:

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

Folgende:

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

Sollte jetzt gelingen.

Eine andere Möglichkeit wäre, auch auf die ungültig machen Methode, und nehmen Sie etwas Zeit, um Ihre Verbindung zu ersetzen.


5
2018-01-29 18:07