launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #29536
[Merge] ~cjwatson/lp-archive:talisker into lp-archive:main
Colin Watson has proposed merging ~cjwatson/lp-archive:talisker into lp-archive:main.
Commit message:
Add talisker support
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/lp-archive/+git/lp-archive/+merge/435624
This is a more capable WSGI server than the Flask development server (mainly via Gunicorn, but also with some of its own extensions), and it's what we use in most of our other services. The Flask development server warns on startup that it shouldn't be used in production.
Dependencies MP: https://code.launchpad.net/~cjwatson/lp-archive/+git/dependencies/+merge/435623
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/lp-archive:talisker into lp-archive:main.
diff --git a/.mypy.ini b/.mypy.ini
index b68e791..661e306 100644
--- a/.mypy.ini
+++ b/.mypy.ini
@@ -4,5 +4,8 @@ python_version = 3.10
[mypy-flask_caching.*]
ignore_missing_imports = true
+[mypy-talisker.*]
+ignore_missing_imports = true
+
[mypy-tomllib.*]
ignore_missing_imports = true
diff --git a/lp_archive/__init__.py b/lp_archive/__init__.py
index 393afdf..dc1b052 100644
--- a/lp_archive/__init__.py
+++ b/lp_archive/__init__.py
@@ -9,7 +9,8 @@ except ModuleNotFoundError:
import tomli as tomllib # type: ignore
from typing import Any
-from flask import Flask
+import talisker.flask
+from flask import Flask, jsonify
from lp_archive import archive, root, routing
from lp_archive.cache import cache
@@ -27,4 +28,20 @@ def create_app(test_config: dict[str, Any] | None = None) -> Flask:
root.init_app(app)
archive.init_app(app)
cache.init_app(app)
+
+ talisker.flask.register(app)
+ # Common Talisker service health check.
+ for layout in app.config.get("LAYOUTS", []):
+ host = layout["host"]
+ app.add_url_rule(
+ "/_status/check",
+ endpoint=f"{host}_health_check",
+ view_func=lambda: (jsonify(ok=True), 200),
+ host=host,
+ )
+
return app
+
+
+# Gunicorn entry point.
+application = create_app()
diff --git a/requirements.in b/requirements.in
index 74d902b..6124191 100644
--- a/requirements.in
+++ b/requirements.in
@@ -1,3 +1,4 @@
Flask
Flask-Caching
+talisker[flask,gunicorn]
tomli; python_version < "3.11"
diff --git a/requirements.txt b/requirements.txt
index 2330d25..08a238b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,19 +1,30 @@
#
-# This file is autogenerated by pip-compile with python 3.10
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
#
# pip-compile
#
+blinker==1.5
+ # via talisker
cachelib==0.9.0
# via flask-caching
+certifi==2022.12.7
+ # via requests
+charset-normalizer==2.1.1
+ # via requests
click==8.1.3
# via flask
flask==2.2.2
# via
# -r requirements.in
# flask-caching
+ # talisker
flask-caching==2.0.1
# via -r requirements.in
+gunicorn==20.1.0
+ # via talisker
+idna==3.4
+ # via requests
itsdangerous==2.1.2
# via flask
jinja2==3.1.2
@@ -22,7 +33,20 @@ markupsafe==2.1.1
# via
# jinja2
# werkzeug
+requests==2.28.1
+ # via talisker
+statsd==3.3.0
+ # via talisker
+talisker[flask,gunicorn]==0.21.3
+ # via -r requirements.in
tomli==2.0.1 ; python_version < "3.11"
# via -r requirements.in
+urllib3==1.26.14
+ # via requests
werkzeug==2.2.2
- # via flask
+ # via
+ # flask
+ # talisker
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/setup.cfg b/setup.cfg
index 00dc7cd..d9772fe 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -19,6 +19,7 @@ packages = find:
install_requires =
Flask
Flask-Caching
+ talisker[flask,gunicorn]
tomli;python_version < "3.11"
python_requires = >=3.10
diff --git a/tests/test_root.py b/tests/test_root.py
index 50656de..71a7f87 100644
--- a/tests/test_root.py
+++ b/tests/test_root.py
@@ -6,3 +6,10 @@ def test_root(client):
response = client.get("/", headers=[("Host", "snapshot.ubuntu.test")])
assert response.data == b"Launchpad archive service.\n"
assert response.headers["Content-Type"] == "text/plain"
+
+
+def test_health_check(client):
+ response = client.get(
+ "/_status/check", headers=[("Host", "snapshot.ubuntu.test")]
+ )
+ assert response.get_json() == {"ok": True}