jenkins-bot has submitted this change and it was merged.

Change subject: Add timeout param to limit query lifespan
......................................................................


Add timeout param to limit query lifespan

Brutally murders database connection after a set interval, raising
an OperationalError.  The Connection instance is useless afterward
and should be re-instantiated.

Change-Id: I0fca9533bb6c1e2bbf3cd88b4e298ac7e3d07335
---
M database/db.py
1 file changed, 32 insertions(+), 13 deletions(-)

Approvals:
  Awight: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/database/db.py b/database/db.py
index 4265627..159bb9f 100644
--- a/database/db.py
+++ b/database/db.py
@@ -4,6 +4,7 @@
 import MySQLdb as Dbi
 import atexit
 import os
+import threading
 
 from signal import signal, SIGTERM, SIG_DFL
 from process.logging import Logger as log
@@ -11,32 +12,50 @@
 
 class Connection(object):
     def __init__(self, debug=False, **kw):
+        self.connectionArgs = kw
         self.db_conn = Dbi.connect(**kw)
         self.debug = debug
+        self.connection_id = self.execute('SELECT CONNECTION_ID() AS cid', 
None, 0)[0]['cid']
 
     def close(self):
         self.db_conn.commit()
 
-    def execute(self, sql, params=None):
+    def execute(self, sql, params=None, timeout = 0):
         cursor = self.db_conn.cursor(cursorclass=Dbi.cursors.DictCursor)
-       
+        deathClock = None
+
         if self.debug:
             if params:
                 log.debug(str(sql) + " % " + repr(params))
             else:
                 log.debug(str(sql))
 
-        if params:
-            cursor.execute(sql, params)
-        elif hasattr(sql, 'uninterpolated_sql') and sql.params:
-            cursor.execute(sql.uninterpolated_sql(), sql.params)
-        else:
-            cursor.execute(str(sql))
-        #for row in cursor.fetchall():
-        #      yield row
-        out = cursor.fetchall()
-        cursor.close()
-        return out
+        if timeout > 0:
+            deathClock = threading.Timer(timeout, self.kill_connection)
+            deathClock.start()
+
+        try:
+            if params:
+                cursor.execute(sql, params)
+            elif hasattr(sql, 'uninterpolated_sql') and sql.params:
+                cursor.execute(sql.uninterpolated_sql(), sql.params)
+            else:
+                cursor.execute(str(sql))
+            #for row in cursor.fetchall():
+            #  yield row
+            out = cursor.fetchall()
+            cursor.close()
+            return out
+        finally:
+            if deathClock is not None:
+                deathClock.cancel()
+
+    def kill_connection(self):
+        log.warn('Query taking too long - killing connection 
{}'.format(self.connection_id))
+        killerConnection = Dbi.connect(**self.connectionArgs)
+        cursor = killerConnection.cursor()
+        cursor.execute('KILL CONNECTION {}'.format(self.connection_id))
+        killerConnection.close()
 
     def execute_paged(self, query, pageIndex, pageSize = 1000, dir = 'ASC'):
         """ Execute a paged query. This will yield a dictionary of the results

-- 
To view, visit https://gerrit.wikimedia.org/r/197205
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I0fca9533bb6c1e2bbf3cd88b4e298ac7e3d07335
Gerrit-PatchSet: 5
Gerrit-Project: wikimedia/fundraising/tools
Gerrit-Branch: master
Gerrit-Owner: Ejegg <[email protected]>
Gerrit-Reviewer: Awight <[email protected]>
Gerrit-Reviewer: Ejegg <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to