Skip to content

Commit 9c8a402

Browse files
authored
wsgi tuning setup config (#1947)
* will cleanup a little more before final * cleanup * EOF * instructions update * Small doc update
1 parent 0358ba6 commit 9c8a402

File tree

6 files changed

+198
-1
lines changed

6 files changed

+198
-1
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,4 @@ celerybeat-schedule
126126
docker-compose.*.yml
127127

128128
.python-version
129+
/locustfile.py
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
=======================================
2+
Setting up uWsgi tuning for MITx Online
3+
=======================================
4+
5+
This setup satisfies the testing to help with tuning as mentioned in this `Discusssion Post <https://github.com/mitodl/hq/discussions/393>`_
6+
7+
Largely borrowed from work on OCW studio:
8+
9+
| `Adding uWSGI stats <https://github.com/mitodl/ocw-studio/pull/1898/>`_
10+
| `Tuning the App <https://github.com/mitodl/ocw-studio/pull/1886/>`_
11+
12+
13+
******************
14+
To set up locally:
15+
******************
16+
17+
Set up uwsgitop
18+
---------------
19+
1. Install uwsgitop: ``docker compose run --rm web poetry add uwsgitop``
20+
2. Set UWSGI_RELOAD_ON_RSS in your .env to a high value (e.g. 500)
21+
3. Set UWSGI_MAX_REQUESTS in your .env to a high value (e.g. 10000)
22+
4. ``docker compose build``
23+
5. ``docker compose up``
24+
6. In a new terminal window/tab, ``docker compose exec web uwsgitop /tmp/uwsgi-stats.sock``
25+
7. You should see your application's memory usage without usage. Ready to go.
26+
27+
28+
Set up Locust
29+
-------------
30+
1. Install Locust: ``docker compose run --rm web poetry add locust``
31+
2. Add locust to your docker-compose.yml locally, under services:
32+
33+
.. code-block:: shell
34+
35+
locust:
36+
image: locustio/locust
37+
ports:
38+
- "8089:8089"
39+
volumes:
40+
- ./:/src
41+
command: >
42+
-f /src/locustfile.py
43+
44+
3. Add the following to the web block, at the level of, and directly after, ``build``:
45+
46+
.. code-block:: shell
47+
48+
deploy:
49+
resources:
50+
limits:
51+
cpus: "2"
52+
memory: "1g"
53+
54+
4. Add locustfile.py. There is an example file at ``locustfile.py.example`` in the root of the repo. ``cp locustfile.py.example locustfile.py`` will copy it over as is. Change variables and/or add tests as needed.
55+
56+
Put it all together
57+
-------------------
58+
59+
1. Run ``docker-compose build``
60+
2. Run ``docker-compose up``
61+
3. You can use locust from ``http://0.0.0.0:8089/`` in a browser
62+
4. You can use uwsgitop in a terminal with ``docker compose exec web uwsgitop /tmp/uwsgi-stats.sock``
63+
64+
******************
65+
To test:
66+
******************
67+
68+
Coming soon!

locustfile.py.example

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import logging
2+
from locust import HttpUser, task, between, events
3+
4+
5+
def _get_product_json(response_json, page_type):
6+
logging.info(f'User was displayed {response_json["count"]} {page_type}(s)')
7+
pages = response_json["results"][:5]
8+
return [page["readable_id"] for page in pages]
9+
10+
11+
class DjangoAdminUser(HttpUser):
12+
wait_time = between(1, 5)
13+
14+
def on_start(self):
15+
self.client.get("/admin/login/")
16+
self.login()
17+
18+
def login(self):
19+
csrf_token = self.client.cookies['csrftoken']
20+
self.client.post(
21+
"/admin/login/",
22+
{
23+
"username": "[email protected]",
24+
"password": "edx",
25+
"csrfmiddlewaretoken": csrf_token,
26+
},
27+
headers={"Referer": "/admin/login/"},
28+
)
29+
30+
@task
31+
def navigate_through_course_areas(self):
32+
logging.info(f"{self} has started to surf")
33+
self._navigate_to_home_page()
34+
programs, courses = self._navigate_to_catalog()
35+
self._navigate_to_product_page("program", programs)
36+
self._navigate_to_product_page("course", courses)
37+
self._navigate_to_checkout_page()
38+
logging.info(f"{self} has gone off to learn")
39+
40+
def _navigate_to_catalog(self):
41+
endpoints = [
42+
"/api/users/me",
43+
"/api/departments/",
44+
"/api/users/me",
45+
]
46+
logging.info(f"User {self} opening catalog")
47+
self._navigate_to_endpoints(endpoints)
48+
with self.client.get("/api/programs/?page=1&live=true", catch_response=True) as response:
49+
program_json = _get_product_json(response.json(), "program")
50+
with self.client.get("/api/courses/?page=1&live=true&page__live=true&courserun_is_enrollable=true",
51+
catch_response=True) as response:
52+
course_json = _get_product_json(response.json(), "course")
53+
return program_json, course_json
54+
55+
def _navigate_to_home_page(self):
56+
logging.info("User (%r) opening Home Page")
57+
with self.client.get("/api/users/me", catch_response=True) as response:
58+
logging.info(response.status_code)
59+
60+
def _navigate_to_checkout_page(self):
61+
logging.info("User (%r) opening Checkout Page")
62+
endpoints = [
63+
"/api/users/me",
64+
"/api/checkout/cart",
65+
]
66+
self._navigate_to_endpoints(endpoints)
67+
68+
def _navigate_to_product_page(self, product_type, response_json):
69+
logging.info(response_json)
70+
for page in response_json:
71+
logging.info(f"User opened {product_type} page for {page}")
72+
endpoints = [
73+
"/api/users/me",
74+
"/api/program_enrollments/",
75+
"/api/users/me",
76+
f"/api/course_runs/?relevant_to={page}",
77+
]
78+
if product_type == "course":
79+
endpoints += [
80+
f"/api/courses/?readable_id={page}&live=true",
81+
]
82+
elif product_type == "program":
83+
endpoints += [
84+
f"/api/programs/?readable_id={page}",
85+
]
86+
self._navigate_to_endpoints(endpoints)
87+
88+
def _navigate_to_endpoints(self, endpoints):
89+
for endpoint in endpoints:
90+
logging.info(f"endpoint: {endpoint}")
91+
with self.client.get(endpoint, catch_response=True) as response:
92+
logging.info(f"status: {response.status_code}")

poetry.lock

+35-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ uwsgi = "^2.0.19"
8383
wagtail = "^5.0"
8484
hypothesis = "4.23.9"
8585
posthog = "^3.0.1"
86+
uwsgitop = "^0.11"
8687

8788

8889
[tool.poetry.group.dev.dependencies]

uwsgi.ini

+1
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ endif =
4545
if-not-env = UWSGI_POST_BUFFERING
4646
post-buffering = 65535
4747
endif =
48+
stats = /tmp/uwsgi-stats.sock

0 commit comments

Comments
 (0)