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

Change subject: Add proper query killer
......................................................................


Add proper query killer

Change-Id: I7b9c8e505c4992db088b25d0c8213d8e4290eec1
---
M quarry/web/app.py
M quarry/web/models/queryresult.py
M quarry/web/static/css/query/view.css
M quarry/web/static/js/query/view.js
M quarry/web/templates/query/view.html
M tables.sql
6 files changed, 70 insertions(+), 23 deletions(-)

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



diff --git a/quarry/web/app.py b/quarry/web/app.py
index 23a994f..5f122d0 100644
--- a/quarry/web/app.py
+++ b/quarry/web/app.py
@@ -3,11 +3,12 @@
 import pymysql
 from models.user import User
 from models.query import Query, QueryRevision, QueryRun
-from models.queryresult import QuerySuccessResult, QueryErrorResult
+from models.queryresult import QuerySuccessResult, QueryErrorResult, 
QueryKilledResult
 import json
 import time
 import os
 from celery import Celery
+from celery.exceptions import SoftTimeLimitExceeded
 
 
 app = Flask(__name__)
@@ -50,29 +51,52 @@
 
 
 @celery.task
-def run_query(query_run_id):
-    qrun = QueryRun.get_by_id(query_run_id)
-    qrun.status = QueryRun.STATUS_RUNNING
-    qrun.save()
-    start_time = time.clock()
+def kill_query(thread_id):
     cur = g.replica.cursor()
     try:
-        cur.execute(qrun.query_rev.text)
-        total_time = time.clock() - start_time
-        result = []
-        result.append(make_result(cur))
-        while cur.nextset():
-            result.append(make_result(cur))
-        qresult = QuerySuccessResult(qrun, total_time, result, 
app.config['OUTPUT_PATH_TEMPLATE'])
-        qrun.status = QueryRun.STATUS_COMPLETE
-    except pymysql.DatabaseError as e:
-        total_time = time.clock() - start_time
-        qresult = QueryErrorResult(qrun, total_time, 
app.config['OUTPUT_PATH_TEMPLATE'], e.args[1])
-        qrun.status = QueryRun.STATUS_FAILED
+        cur.execute("KILL QUERY %s", thread_id)
+    except pymysql.InternalError as e:
+        if e.args[0] == 1094:  # Error code for 'no such thread'
+            print 'Query already killed'
+        else:
+            raise
     finally:
         cur.close()
-    qresult.output()
-    qrun.save()
+
+
+@celery.task
+def run_query(query_run_id):
+    qrun = QueryRun.get_by_id(query_run_id)
+    try:
+        qrun = QueryRun.get_by_id(query_run_id)
+        qrun.status = QueryRun.STATUS_RUNNING
+        qrun.save()
+        start_time = time.clock()
+        cur = g.replica.cursor()
+        try:
+            cur.execute(qrun.query_rev.text)
+            result = []
+            result.append(make_result(cur))
+            while cur.nextset():
+                result.append(make_result(cur))
+            total_time = time.clock() - start_time
+            qresult = QuerySuccessResult(qrun, total_time, result, 
app.config['OUTPUT_PATH_TEMPLATE'])
+            qrun.status = QueryRun.STATUS_COMPLETE
+        except pymysql.DatabaseError as e:
+            total_time = time.clock() - start_time
+            qresult = QueryErrorResult(qrun, total_time, 
app.config['OUTPUT_PATH_TEMPLATE'], e.args[1])
+            qrun.status = QueryRun.STATUS_FAILED
+        finally:
+            cur.close()
+        qresult.output()
+        qrun.save()
+    except SoftTimeLimitExceeded:
+        total_time = time.clock() - start_time
+        kill_query.delay(g.replica.thread_id())
+        qrun.state = QueryRun.STATUS_KILLED
+        qrun.save()
+        qresult = QueryKilledResult(qrun, total_time, 
app.config['OUTPUT_PATH_TEMPLATE'])
+        qresult.output()
 
 
 def get_user():
diff --git a/quarry/web/models/queryresult.py b/quarry/web/models/queryresult.py
index 8016df2..6f9bf73 100644
--- a/quarry/web/models/queryresult.py
+++ b/quarry/web/models/queryresult.py
@@ -45,3 +45,14 @@
             'error': self.error
         }
         super(QueryErrorResult, self).output()
+
+
+class QueryKilledResult(QueryResult):
+    def __init__(self, query_run, total_time, path_template):
+        super(QueryKilledResult, self).__init__(query_run, path_template, 
total_time)
+
+    def output(self):
+        self.output_data = {
+            'result': 'killed'
+        }
+        super(QueryKilledResult, self).output()
diff --git a/quarry/web/static/css/query/view.css 
b/quarry/web/static/css/query/view.css
index 56377f1..7c1b0b4 100644
--- a/quarry/web/static/css/query/view.css
+++ b/quarry/web/static/css/query/view.css
@@ -17,6 +17,6 @@
     overflow-x: scroll;
 }
 
-#query-result-success, #query-result-error, #query-progress {
+#query-result-success, #query-result-error, #query-progress, 
#query-result-killed {
     display: none;
 }
diff --git a/quarry/web/static/js/query/view.js 
b/quarry/web/static/js/query/view.js
index 2d77f23..549dff2 100644
--- a/quarry/web/static/js/query/view.js
+++ b/quarry/web/static/js/query/view.js
@@ -58,12 +58,20 @@
                     $("#query-result-error").hide();
 
                     $("#query-result-success").show();
+                    $("#query-result-killed").hide();
                 } else if (d.result === 'error') {
                     $("#error-time").text(d.time.toFixed(4) + "s");
                     $("#query-error-message").text(d.error);
                     $("#query-progress").hide();
                     $("#query-result-error").show();
                     $("#query-result-success").hide();
+                    $("#query-result-killed").hide();
+                } else if (d.result === 'killed' ) {
+                    $("#killed-time").text(d.time.toFixed(4) + "s");
+                    $("#query-progress").hide();
+                    $("#query-result-error").hide();
+                    $("#query-result-success").hide();
+                    $("#query-result-killed").show();
                 }
             } ).fail( function() {
                 setTimeout( checkOutput, 5000 );
diff --git a/quarry/web/templates/query/view.html 
b/quarry/web/templates/query/view.html
index 953b7f8..8dfa3e9 100644
--- a/quarry/web/templates/query/view.html
+++ b/quarry/web/templates/query/view.html
@@ -33,9 +33,12 @@
             </h3>
         </div>
         <div id="query-result-error">
-            <h3>Error! <small id="error-time"></span></h3>
+            <h3>Error! <small id="error-time"></small></h3>
             <pre id="query-error-message"></pre>
         </div>
+        <div id="query-result-killed">
+            <h3>Query killed! <small id="killed-time"></small></h3>
+        </div>
         <div id="query-progress">
             <h3>Query running...</h3>
         </div>
diff --git a/tables.sql b/tables.sql
index 5a4fdcc..72f8041 100644
--- a/tables.sql
+++ b/tables.sql
@@ -8,7 +8,8 @@
     user_id INT UNSIGNED NOT NULL,
     title VARCHAR(1024) BINARY NOT NULL,
     latest_rev INT UNSIGNED,
-    last_touched TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP
+    last_touched TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP,
+    parent_id INT UNSIGNED
 );
 
 CREATE TABLE query_revision(

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I7b9c8e505c4992db088b25d0c8213d8e4290eec1
Gerrit-PatchSet: 2
Gerrit-Project: analytics/quarry/web
Gerrit-Branch: master
Gerrit-Owner: Yuvipanda <yuvipa...@gmail.com>
Gerrit-Reviewer: Legoktm <legoktm.wikipe...@gmail.com>
Gerrit-Reviewer: Springle <sprin...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to