From 75a35e64d52b521eb32e65f733b136272e6c891b Mon Sep 17 00:00:00 2001 From: framawiki <21953768+framawiki@users.noreply.github.com> Date: Mon, 29 May 2023 13:44:12 +0200 Subject: [PATCH] Advertise on replag (#22) Bug: T60841 --- Dockerfile | 2 +- docker-replica/replica.sql | 11 +++++++++ quarry/web/app.py | 3 ++- quarry/web/static/templates/compiled.js | 7 ++++++ quarry/web/static/templates/query-status.html | 8 +++++++ quarry/web/webhelpers.py | 20 ++++++++++------ quarry/web/worker.py | 23 ++++++++++++++----- tests/test_worker.py | 2 +- 8 files changed, 60 insertions(+), 16 deletions(-) diff --git a/Dockerfile b/Dockerfile index 88c83f9..dfc0954 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Use official python base image, small and debian edition -FROM amd64/python:3.7.3-slim +FROM amd64/python:3.7.16-slim ARG purpose=dev diff --git a/docker-replica/replica.sql b/docker-replica/replica.sql index 20628a0..81cfeb1 100644 --- a/docker-replica/replica.sql +++ b/docker-replica/replica.sql @@ -1197,3 +1197,14 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `heartbeat_p` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; +USE `heartbeat_p`; +GRANT SELECT ON heartbeat_p.* TO 'repl'@'%'; + +CREATE TABLE `heartbeat` ( + `shard` varbinary(10) NOT NULL, + `last_updated` varbinary(26) NOT NULL, + `lag` decimal(25, 4) +) ENGINE=InnoDB DEFAULT CHARSET=binary; +INSERT INTO heartbeat_p.heartbeat (shard, last_updated, `lag`) VALUES (0x7331, 0x323032332D30352D32355430353A33393A33382E303030393930, 278631.9990); diff --git a/quarry/web/app.py b/quarry/web/app.py index 21b6df9..db64c93 100644 --- a/quarry/web/app.py +++ b/quarry/web/app.py @@ -44,7 +44,8 @@ def setup_context(): def kill_context(exception=None): - g.conn.close_all() + if g.conn: + g.conn.close_all() del g.replica.connection diff --git a/quarry/web/static/templates/compiled.js b/quarry/web/static/templates/compiled.js index 4b510d9..8cb0270 100644 --- a/quarry/web/static/templates/compiled.js +++ b/quarry/web/static/templates/compiled.js @@ -156,6 +156,13 @@ output += "\n"; ; } output += "\n"; +if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "extra")),"replag")) { +output += "\n
\n

Replication lag

\n

The database on which this query was executed has a synchronization delay with the wiki.\n This can be caused by maintenance or incident on database, and should be resolved soon.
\n The modifications that was made in last "; +output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "extra")),"replag"), env.opts.autoescape); +output += " on the wiki are not taken into account in results bellow.
\n

\n"; +; +} +output += "\n"; if(parentTemplate) { parentTemplate.rootRenderFunc(env, context, frame, runtime, cb); } else { diff --git a/quarry/web/static/templates/query-status.html b/quarry/web/static/templates/query-status.html index 3badc44..a4e23d3 100644 --- a/quarry/web/static/templates/query-status.html +++ b/quarry/web/static/templates/query-status.html @@ -13,3 +13,11 @@ {% endif %} {% endif %} +{% if extra.replag %} +
+

Replication lag

+

The database on which this query was executed has a synchronization delay with the wiki. + This can be caused by maintenance or incident on database, and should be resolved soon.
+ The modifications that was made in last {{ extra.replag }} on the wiki are not taken into account in results bellow.
+

+{% endif %} diff --git a/quarry/web/webhelpers.py b/quarry/web/webhelpers.py index 55ca19b..f435591 100644 --- a/quarry/web/webhelpers.py +++ b/quarry/web/webhelpers.py @@ -4,8 +4,7 @@ templatehelpers = Blueprint("templatehelpers", __name__) -@templatehelpers.add_app_template_filter -def timesince(dt, default="just now"): +def get_pretty_delay(diff, suffix="", default="just now"): """ Returns string representing "time since" e.g. 3 days ago, 5 hours ago etc. @@ -13,9 +12,6 @@ def timesince(dt, default="just now"): From http://flask.pocoo.org/snippets/33/ """ - now = datetime.utcnow() - diff = now - dt - periods = ( (diff.days // 365, "year", "years"), (diff.days // 30, "month", "months"), @@ -27,8 +23,18 @@ def timesince(dt, default="just now"): ) for period, singular, plural in periods: - if period: - return "%d %s ago" % (period, singular if period == 1 else plural) + return "%d %s %s" % ( + period, + singular if period == 1 else plural, + suffix, + ) return default + + +@templatehelpers.add_app_template_filter +def timesince(dt, default="just now"): + now = datetime.utcnow() + diff = now - dt + return get_pretty_delay(diff, suffix="ago", default=default) diff --git a/quarry/web/worker.py b/quarry/web/worker.py index 6b31272..871384e 100644 --- a/quarry/web/worker.py +++ b/quarry/web/worker.py @@ -1,6 +1,7 @@ import json import os import timeit +from datetime import timedelta from celery import Celery from celery.signals import worker_process_init, worker_process_shutdown @@ -13,6 +14,7 @@ from .results import SQLiteResultWriter from .replica import Replica from .utils import monkey as _unused # noqa: F401 +from .webhelpers import get_pretty_delay __dir__ = os.path.dirname(__file__) @@ -34,6 +36,11 @@ conn = None +def get_replag(cur): + cur.execute("SELECT lag FROM heartbeat_p.heartbeat;") + return int(cur.fetchall()[0][0]) + + @worker_process_init.connect def init(*args, **kwargs): global conn @@ -107,12 +114,16 @@ def run_query(query_run_id): output.close() stoptime = timeit.default_timer() qrun.status = QueryRun.STATUS_COMPLETE - qrun.extra_info = json.dumps( - { - "resultsets": output.get_resultsets(), - "runningtime": "%.2f" % (stoptime - starttime), - } - ) + extra_info = { + "resultsets": output.get_resultsets(), + "runningtime": "%.2f" % (stoptime - starttime), + } + # Add replica lag if it's above threshold, to be displayed to user + replag = get_replag(cur) + if replag > 180: # 3 minutes + extra_info["replag"] = get_pretty_delay(timedelta(seconds=replag)) + qrun.extra_info = json.dumps(extra_info) + celery_log.info("Completed run for qrun:%s successfully", qrun.id) conn.session.add(qrun) conn.session.commit() diff --git a/tests/test_worker.py b/tests/test_worker.py index 21e83eb..afb1613 100644 --- a/tests/test_worker.py +++ b/tests/test_worker.py @@ -19,7 +19,7 @@ def __init__(self): self.nextsetcalled = False def fetchall(self): - return [["a", "b", "c"], ["1", "2", "3"]] + return [[1, "b", "c"], ["1", "2", "3"]] def fetchmany(self, _count): if not self.called: