Skip to content

Commit 75c110a

Browse files
committed
cmg: Implement CogStack Model Gateway & Scheduler
This commit introduces the CogStack Model Gateway and Scheduler services, along with a common package for managing external components, including a database, an object store, and a message queue. More specifically, the project is deployed through a docker-compose file and consists of the following core services: * Gateway: A FastAPI server that receives requests from the user targetting a deployed model server. These are submitted as tasks to be executed by the downstream services. It also exposes endpoints for listing the available model services, as well as fetching information about previously submitted tasks. * Database: A PostgreSQL database for storing information about the submitted tasks, most importantly their status, IDs for tracking them across different services (e.g. other stores deployed as part of the CogStack Model Gateway as well as the model tracking server), and references to their results. * Queue: A RabbitMQ message queue for managing the tasks submitted to the system. The queue is used to distribute the tasks to the scheduler, which is in turn responsible for executing them. * Object Store: A MinIO object store for serialising larger user requests (e.g. attached files or request bodies) that will be picked up an reconstructed by the scheduler, as well as for storing task results. The results are stored as objects with a prefix that corresponds to the corresponding task's UUID. * Scheduler: A Python application that listens to the message queue for new tasks and executes them by forwarding them to the appropriate model server for execution. Currently, it is also responsible for monitoring the execution of long-running tasks and updating all relevant stores with the task's status and results. The E2E workflow looks something like this: * The user submits a task to the Gateway, specifying the desired model server and action as part of the request (i.e. path parameters) * The Gateway receives the task and creates an entry in the database, generating a UUID that can be used to track the task across the CMG components and setting its status to "PENDING". * The Gateway deconstructs the request, extracting information like the target endpoint and action, the content type, query params, body, and attached files. The request body and the attached files are serialised and stored in the object store. * The Gateway creates a message containing all data necessary for reconstructing the request and sends it to the queue. For objects stored in the object store, it includes a reference instead, so that the queue isn't cluttered with large payloads. While all messages are assigned the same priority at the moment, we intend to extend the Gateway to calculate an appropriate value based on the information received. * The Scheduler listens to the queue for new messages and picks them up as they come. * The Scheduler reconstructs the request and forwards it to the appropriate model server for execution, setting its status in the database to "SCHEDULED" and acknowledging the message delivery. * The model server executes the task and returns a response. * If the server signifies the completion of the task (i.e. short-running task that completes synchronously), the Scheduler stores the result in the object store, updates the task's status to "SUCCEEDED" or "FAILED" depending on the response, and adds a reference to the results in a bucket in the object store. * If the server signifies the task was accepted (i.e. long-running task) the Scheduler updates the task's status to "RUNNING" and starts periodically checking its status by monitoring the model tracking server (MLflow). Once the task is completed, the MLflow UI URL is serialised and uploaded to MinIO, while the task's status is updated to "SUCCEEDED" or "FAILED" depending on the response. * In the future we will extend this service to send a notification to the user that requested the task execution. Monitoring the task execution will likely be moved out of th scheduler and into a separate service altogether. In the meantime, the user can query the Gateway for the task's status and results and even ask for a URL to directly download the file containing the results from the object store. Signed-off-by: Phoevos Kalemkeris <phoevos.kalemkeris@ucl.ac.uk.com>
0 parents  commit 75c110a

36 files changed

+6463
-0
lines changed

.github/workflows/ci.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Python tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: "3.12"
21+
22+
- name: Install Poetry
23+
run: |
24+
curl -sSL https://install.python-poetry.org | python3 -
25+
26+
- name: Install dependencies
27+
run: |
28+
poetry install --with dev
29+
30+
- name: Run tests
31+
run:
32+
poetry run pytest

.gitignore

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
share/python-wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.nox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
*.py,cover
50+
.hypothesis/
51+
.pytest_cache/
52+
cover/
53+
54+
# Translations
55+
*.mo
56+
*.pot
57+
58+
# Django stuff:
59+
*.log
60+
local_settings.py
61+
db.sqlite3
62+
db.sqlite3-journal
63+
64+
# Flask stuff:
65+
instance/
66+
.webassets-cache
67+
68+
# Scrapy stuff:
69+
.scrapy
70+
71+
# Sphinx documentation
72+
docs/_build/
73+
74+
# PyBuilder
75+
.pybuilder/
76+
target/
77+
78+
# Jupyter Notebook
79+
.ipynb_checkpoints
80+
81+
# IPython
82+
profile_default/
83+
ipython_config.py
84+
85+
# pyenv
86+
# For a library or package, you might want to ignore these files since the code is
87+
# intended to run in multiple environments; otherwise, check them in:
88+
# .python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# poetry
98+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99+
# This is especially recommended for binary packages to ensure reproducibility, and is more
100+
# commonly ignored for libraries.
101+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102+
#poetry.lock
103+
104+
# pdm
105+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106+
#pdm.lock
107+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108+
# in version control.
109+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110+
.pdm.toml
111+
.pdm-python
112+
.pdm-build/
113+
114+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115+
__pypackages__/
116+
117+
# Celery stuff
118+
celerybeat-schedule
119+
celerybeat.pid
120+
121+
# SageMath parsed files
122+
*.sage.py
123+
124+
# Environments
125+
.env
126+
.venv
127+
env/
128+
venv/
129+
ENV/
130+
env.bak/
131+
venv.bak/
132+
133+
# Spyder project settings
134+
.spyderproject
135+
.spyproject
136+
137+
# Rope project settings
138+
.ropeproject
139+
140+
# mkdocs documentation
141+
/site
142+
143+
# mypy
144+
.mypy_cache/
145+
.dmypy.json
146+
dmypy.json
147+
148+
# Pyre type checker
149+
.pyre/
150+
151+
# pytype static type analyzer
152+
.pytype/
153+
154+
# ruff
155+
.ruff_cache/
156+
157+
# Cython debug symbols
158+
cython_debug/
159+
160+
# PyCharm
161+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
162+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
163+
# and can be added to the global gitignore or merged into this file. For a more nuclear
164+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
165+
#.idea/
166+
167+
# VS Code
168+
.vscode/

.pre-commit-config.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
default_install_hook_types:
2+
- pre-commit
3+
- post-checkout
4+
- post-merge
5+
6+
repos:
7+
- repo: https://github.com/pre-commit/pre-commit-hooks
8+
rev: v5.0.0
9+
hooks:
10+
- id: trailing-whitespace
11+
- id: end-of-file-fixer
12+
- id: check-yaml
13+
- id: check-added-large-files
14+
- id: check-json
15+
- repo: https://github.com/astral-sh/ruff-pre-commit
16+
rev: v0.8.0
17+
hooks:
18+
- id: ruff
19+
entry: poetry run ruff check --force-exclude --fix
20+
- id: ruff-format
21+
entry: poetry run ruff format --force-exclude
22+
- repo: https://github.com/python-poetry/poetry
23+
rev: 1.8.4
24+
hooks:
25+
- id: poetry-check
26+
- id: poetry-lock
27+
- id: poetry-install

CONTRIBUTING.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Contributing
2+
3+
Thank you for your interest in contributing to the project! Here are some useful instructions for
4+
getting you started.
5+
6+
## Installation
7+
8+
1. Clone the repository:
9+
10+
```shell
11+
git clone https://github.com/CogStack/CogStack-ModelGateway.git cms-gateway
12+
cd cms-gateway
13+
```
14+
15+
2. Install Poetry if you haven't already:
16+
17+
```shell
18+
curl -sSL https://install.python-poetry.org | python3 -
19+
```
20+
21+
3. Install the project dependencies:
22+
23+
```shell
24+
poetry install --with dev
25+
```
26+
27+
## Pre-commit Hooks
28+
29+
We use pre-commit hooks to ensure code quality. To set them up, follow these steps:
30+
31+
1. Install pre-commit if you haven't already:
32+
33+
```shell
34+
pip install pre-commit
35+
```
36+
37+
2. Install the pre-commit hooks to your local Git repository:
38+
39+
```shell
40+
pre-commit install
41+
```
42+
43+
3. (optional) To run the pre-commit hooks manually on all files, use:
44+
45+
```shell
46+
pre-commit run --all-files
47+
```

0 commit comments

Comments
 (0)