]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Testing reveals that we have *no* weak references to any cx_Oracle connections...
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 9 Feb 2016 03:57:02 +0000 (22:57 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 9 Feb 2016 03:57:02 +0000 (22:57 -0500)
yet cx_Oracle still has open sessions that cannot be killed until process dies.
Oracle wins!   Add a completely separate DB reaper script that runs
after py.test is done.

lib/sqlalchemy/testing/provision.py
reap_oracle_dbs.py [new file with mode: 0644]
tox.ini

index ba9754d9001aefbdea6cf78e1fe944a124b53461..6615eabaf5fc54d8e05e410438aa5d64c8ddeeb3 100644 (file)
@@ -5,6 +5,8 @@ from sqlalchemy.util import compat
 from . import config, engines
 import os
 import time
+import logging
+log = logging.getLogger(__name__)
 
 FOLLOWER_IDENT = None
 
@@ -255,18 +257,39 @@ def _oracle_configure_follower(config, ident):
     config.test_schema_2 = "%s_ts2" % ident
 
 
+def _ora_drop_ignore(conn, dbname):
+    try:
+        conn.execute("drop user %s cascade" % dbname)
+        log.info("Reaped db: %s" % dbname)
+        return True
+    except exc.DatabaseError as err:
+        log.warn("couldn't drop db: %s" % err)
+        return False
+
 @_drop_db.for_db("oracle")
 def _oracle_drop_db(cfg, eng, ident):
     with eng.connect() as conn:
-        for row in conn.execute(
-                "select sid, serial# from v$session "
-                "where username='%s'" % ident.upper()):
-            sid, serial = row
-            conn.execute("alter system disconnect session '%s, %s' immediate" % (sid, serial))
-            # conn.execute("alter system kill session '%s, %s'" % (sid, serial))
-        conn.execute("drop user %s cascade" % ident)
-        conn.execute("drop user %s_ts1 cascade" % ident)
-        conn.execute("drop user %s_ts2 cascade" % ident)
+        # cx_Oracle seems to occasionally leak open connections when a large
+        # suite it run, even if we confirm we have zero references to
+        # connection objects.
+        # while there is a "kill session" command in Oracle,
+        # it unfortunately does not release the connection sufficiently.
+        _ora_drop_ignore(conn, ident)
+        _ora_drop_ignore(conn, "%s_ts1" % ident)
+        _ora_drop_ignore(conn, "%s_ts2" % ident)
+
+def reap_oracle_dbs(eng):
+    log.info("Reaping Oracle dbs...")
+    with eng.connect() as conn:
+        to_reap = conn.execute(
+                 "select u.username from all_users u where username "
+                 "like 'TEST_%' and not exists (select username "
+                 "from v$session where username=u.username)")
+        dropped = 0
+        for total, (username, ) in enumerate(to_reap, 1):
+            if _ora_drop_ignore(conn, username):
+                dropped += 1
+        log.info("Dropped %d out of %d stale databases detected", dropped, total)
 
 
 @_follower_url_from_main.for_db("oracle")
diff --git a/reap_oracle_dbs.py b/reap_oracle_dbs.py
new file mode 100644 (file)
index 0000000..ff638a0
--- /dev/null
@@ -0,0 +1,24 @@
+"""Drop Oracle databases that are left over from a 
+multiprocessing test run.
+
+Currently the cx_Oracle driver seems to sometimes not release a
+TCP connection even if close() is called, which prevents the provisioning
+system from dropping a database in-process.
+
+"""
+from sqlalchemy.testing.plugin import plugin_base
+from sqlalchemy.testing import engines
+from sqlalchemy.testing import provision
+import logging
+
+logging.basicConfig()
+logging.getLogger(provision.__name__).setLevel(logging.INFO)
+
+plugin_base.read_config()
+oracle = plugin_base.file_config.get('db', 'oracle')
+from sqlalchemy.testing import provision
+
+engine = engines.testing_engine(oracle, {})
+provision.reap_oracle_dbs(engine)
+
+
diff --git a/tox.ini b/tox.ini
index 83f551fadfed0c65c4f6ce6391b0c85200727286..ef91f44859f651cca102aea60ae512d7fdc911b7 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -60,6 +60,8 @@ passenv=ORACLE_HOME NLS_LANG
 commands=
   {nocext}: sh -c "rm -f lib/sqlalchemy/*.so"
   {env:BASECOMMAND} {env:SQLITE:} {env:POSTGRESQL:} {env:MYSQL:} {env:ORACLE:} {env:MSSQL:} {env:BACKENDONLY:} {env:COVERAGE:} {posargs}
+  {oracle}: python reap_oracle_dbs.py
+
 
 [testenv:pep8]
 deps=flake8