Skip to content

Commit ceb9e3b

Browse files
authored
Merge pull request #1 from eduNEXT/cag/celery-queue
feat: allow to run multiple celery queues and workers
2 parents 59701a9 + dd900b7 commit ceb9e3b

File tree

10 files changed

+182
-27
lines changed

10 files changed

+182
-27
lines changed

.github/workflows/test.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Run tests
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
tests:
8+
runs-on: ubuntu-latest
9+
strategy:
10+
matrix:
11+
python-version: ['3.8', '3.12']
12+
steps:
13+
- uses: actions/checkout@v3
14+
- name: Set up Python ${{ matrix.python-version }}
15+
uses: actions/setup-python@v5
16+
with:
17+
python-version: ${{ matrix.python-version }}
18+
- name: Upgrade pip
19+
run: python -m pip install --upgrade pip
20+
- name: Install dependencies
21+
run: |
22+
pip install .[dev]
23+
- name: Test lint, types, and format
24+
run: make test

README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Celery plugin for [Tutor](https://docs.tutor.edly.io)
2+
3+
A tutor plugin to extend the default LMS and CMS celery workers included in Tutor.
4+
It adds and configures extra deployments running LMS and CMS celery workers where
5+
every deployment will process async tasks routed to a specific queue. Having this
6+
workers separation per queue can help to define the scaling requirements for the Celery
7+
deployments, since having a single queue (the default one) with a single deployment can
8+
lead to unexpected behaviors when running large-scale sites.
9+
10+
## Installation
11+
12+
```shell
13+
pip install git+https://github.com/eduNEXT/tutor-contrib-celery
14+
```
15+
16+
## Usage
17+
18+
```shell
19+
tutor plugins enable celery
20+
```
21+
22+
## Configuration
23+
24+
### Celery queues
25+
26+
By default, tutor-contrib-celery enables the following queues with independent deployments
27+
for each:
28+
29+
- **CMS**: default, high, low (taken from CMS settings [here](https://github.com/openedx/edx-platform/blob/open-release/redwood.master/cms/envs/common.py#L1578-L1582))
30+
- **LMS**: default, high, high_mem (taken from LMS settings [here](https://github.com/openedx/edx-platform/blob/open-release/redwood.master/lms/envs/common.py#L2913-L2917))
31+
32+
> [!NOTE]
33+
> We recommend using [tutor-contrib-pod-autoscaling](https://github.com/eduNEXT/tutor-contrib-pod-autoscaling)
34+
> to setup requested resources and limits.
35+
36+
In case you are using different celery queues than the defaults from Open edX, you can
37+
extend the list by setting `CELERY_WORKER_VARIANTS` on your `config.yml`. The format is the following:
38+
39+
```yaml
40+
CELERY_WORKER_VARIANTS:
41+
lms:
42+
- high
43+
- high_mem
44+
- lms_custom_queue
45+
cms:
46+
- high
47+
- low
48+
- cms_custom_queue
49+
```
50+
51+
This plugin also provides a setting to directly route LMS/CMS tasks to an specific queue. It can extends/overrides
52+
the default `EXPLICIT_QUEUES` setting:
53+
54+
```yaml
55+
CELERY_LMS_EXPLICIT_QUEUES:
56+
lms.djangoapps.grades.tasks.compute_all_grades_for_course:
57+
queue: edx.lms.core.high_mem
58+
CELERY_CMS_EXPLICIT_QUEUES:
59+
cms.djangoapps.contentstore.tasks.import_olx:
60+
queue: edx.cms.core.high
61+
```
62+
63+
License
64+
*******
65+
66+
This software is licensed under the terms of the AGPLv3.

README.rst

Lines changed: 0 additions & 23 deletions
This file was deleted.

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
def load_readme():
10-
with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f:
10+
with io.open(os.path.join(HERE, "README.md"), "rt", encoding="utf8") as f:
1111
return f.read()
1212

1313

@@ -42,10 +42,10 @@ def load_about():
4242
packages=find_packages(exclude=["tests*"]),
4343
include_package_data=True,
4444
python_requires=">=3.7",
45-
install_requires=["tutor>=17.0.0,<18.0.0"],
45+
install_requires=["tutor>=18.0.0,<19.0.0"],
4646
extras_require={
4747
"dev": [
48-
"tutor[dev]>=17.0.0,<18.0.0",
48+
"tutor[dev]>=18.0.0,<19.0.0",
4949
]
5050
},
5151
entry_points={

tutorcelery/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "17.0.0"
1+
__version__ = "18.0.0"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{% for service, variants in CELERY_WORKER_VARIANTS.items() %}
2+
{% for variant in variants%}
3+
{% set deployment = service + "-" + "worker" + "-" + variant.replace("_", "-") %}
4+
---
5+
apiVersion: apps/v1
6+
kind: Deployment
7+
metadata:
8+
name: {{deployment}}
9+
labels:
10+
app.kubernetes.io/name: {{deployment}}
11+
spec:
12+
selector:
13+
matchLabels:
14+
app.kubernetes.io/name: {{deployment}}
15+
template:
16+
metadata:
17+
labels:
18+
app.kubernetes.io/name: {{deployment}}
19+
spec:
20+
securityContext:
21+
runAsUser: 1000
22+
runAsGroup: 1000
23+
containers:
24+
- name: {{deployment}}
25+
image: {{ DOCKER_IMAGE_OPENEDX }}
26+
args:
27+
- "celery"
28+
- "--app={{service}}.celery"
29+
- "worker"
30+
- "--loglevel=info"
31+
- "--hostname=edx.{{service}}.core.{{variant}}.%%h"
32+
- "--max-tasks-per-child=100"
33+
- "--queues=edx.{{service}}.core.{{variant}}"
34+
env:
35+
- name: SERVICE_VARIANT
36+
value: {{service}}
37+
- name: DJANGO_SETTINGS_MODULE
38+
value: {{service}}.envs.tutor.production
39+
volumeMounts:
40+
- mountPath: /openedx/edx-platform/{{service}}/envs/tutor/
41+
name: settings-{{service}}
42+
- mountPath: /openedx/config
43+
name: config
44+
securityContext:
45+
allowPrivilegeEscalation: false
46+
volumes:
47+
- name: settings-{{service}}
48+
configMap:
49+
name: openedx-settings-{{service}}
50+
- name: config
51+
configMap:
52+
name: openedx-config
53+
{% endfor %}
54+
{% endfor %}

tutorcelery/patches/k8s-override

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{% for service in ["lms", "cms"] %}
2+
---
3+
apiVersion: apps/v1
4+
kind: Deployment
5+
metadata:
6+
name: {{service}}-worker
7+
spec:
8+
template:
9+
spec:
10+
containers:
11+
- name: {{service}}-worker
12+
args:
13+
- "celery"
14+
- "--app={{service}}.celery"
15+
- "worker"
16+
- "--loglevel=info"
17+
- "--hostname=edx.{{service}}.core.default.%%h"
18+
- "--max-tasks-per-child=100"
19+
- "--queues=edx.{{service}}.core.default"
20+
{% endfor %}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
try:
2+
EXPLICIT_QUEUES.update({{CELERY_CMS_EXPLICIT_QUEUES}})
3+
except NameError:
4+
EXPLICIT_QUEUES = {{CELERY_CMS_EXPLICIT_QUEUES}}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
try:
2+
EXPLICIT_QUEUES.update({{CELERY_LMS_EXPLICIT_QUEUES}})
3+
except NameError:
4+
EXPLICIT_QUEUES = {{CELERY_LMS_EXPLICIT_QUEUES}}

tutorcelery/plugin.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
# Each new setting is a pair: (setting_name, default_value).
2020
# Prefix your setting names with 'CELERY_'.
2121
("CELERY_VERSION", __version__),
22+
(
23+
"CELERY_WORKER_VARIANTS",
24+
{"lms": ["high", "high_mem"], "cms": ["high", "low"]},
25+
),
26+
("CELERY_LMS_EXPLICIT_QUEUES", {}),
27+
("CELERY_CMS_EXPLICIT_QUEUES", {}),
2228
]
2329
)
2430

0 commit comments

Comments
 (0)