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