Skip to content

connection record not immediately checked back in when connection fails after failed checkout event handler #3419

@sqlalchemy-bot

Description

@sqlalchemy-bot

Migrated issue, originally created by Michael Bayer (@zzzeek)

from sqlalchemy import event
import mock
import sys
import sqlalchemy as sa

engine = sa.create_engine(
    "postgresql://scott:tiger@localhost/test",
    pool_size=1, max_overflow=0, pool_timeout=0, pool_recycle=3600)


@event.listens_for(engine, 'checkout')
def handle_checkout_event(dbapi_con, con_record, con_proxy):
    try:
        with dbapi_con.cursor() as cur:
            cur.execute("SELECT 1")
            cur.fetchone()
    except Exception:
        raise sa.exc.DisconnectionError()

# act as though the DB is turned off
conn = engine.connect()
dbapi_conn = conn.connection.connection
conn.close()

dbapi_conn.close()


def shutdown_backend():
    raise dbapi_conn.OperationalError("closed the connection")

patcher = mock.patch.object(engine.pool, "_creator", shutdown_backend)
patcher.start()

try:
    with engine.begin() as conn:
        pass
except sa.exc.OperationalError as e:
    print >>sys.stderr, "Got an (expected) error: ", e

# sys.exc_clear()

try:
    with engine.begin() as conn:
        pass
except sa.exc.OperationalError as e:
    print >>sys.stderr, "Got an (expected) error: ", e

assert True



the pool checkout fails on the second run because the single ConnectionRecord hasn't been checked in.

diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py
index 0a4cdad..b38aefb 100644
--- a/lib/sqlalchemy/pool.py
+++ b/lib/sqlalchemy/pool.py
@@ -732,7 +732,13 @@ class _ConnectionFairy(object):
                 pool.logger.info(
                     "Disconnection detected on checkout: %s", e)
                 fairy._connection_record.invalidate(e)
-                fairy.connection = fairy._connection_record.get_connection()
+                try:
+                    fairy.connection = \
+                        fairy._connection_record.get_connection()
+                except:
+                    with util.safe_reraise():
+                        fairy._connection_record.checkin()
+
                 attempts -= 1
 
         pool.logger.info("Reconnection attempts exhausted on checkout")

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions