Skip to content

Commit ec82630

Browse files
authored
feat: use supervisord to manage the processes (#194)
Signed-off-by: Anupam Kumar <kyteinsky@gmail.com>
1 parent 0c55c91 commit ec82630

File tree

11 files changed

+179
-107
lines changed

11 files changed

+179
-107
lines changed

.github/workflows/integration-test.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ jobs:
4848
- 'project.toml'
4949
- 'requirements.txt'
5050
- 'logger_config.yaml'
51+
- 'logger_config_em.yaml'
52+
- 'supervisord.conf'
5153
- '.github/workflows/integration-test.yml'
5254
5355
integration:
@@ -181,6 +183,7 @@ jobs:
181183
pip install -r requirements.txt
182184
cp example.env .env
183185
echo "NEXTCLOUD_URL=http://localhost:8080" >> .env
186+
python3 -u ./main_em.py > em_backend_logs 2>&1 &
184187
python3 -u ./main.py > backend_logs 2>&1 &
185188
echo $! > ../pid.txt # Save the process ID (PID)
186189
@@ -260,7 +263,8 @@ jobs:
260263
run: |
261264
cat data/nextcloud.log
262265
echo '--------------------------------------------------'
263-
cat context_chat_backend/backend_logs || echo "No backend logs"
266+
cat context_chat_backend/backend_logs || echo "No main backend logs"
267+
cat context_chat_backend/em_backend_logs || echo "No main backend logs"
264268
echo '--------------------------------------------------'
265269
tail -v -n +1 context_chat_backend/persistent_storage/logs/* || echo "No logs in logs directory"
266270

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ COPY main.py .
4646
COPY main_em.py .
4747
COPY config.?pu.yaml .
4848
COPY logger_config.yaml .
49+
COPY logger_config_em.yaml .
4950
COPY hwdetect.sh .
51+
COPY supervisord.conf /etc/supervisor/supervisord.conf
5052

51-
ENTRYPOINT [ "./dockerfile_scripts/entrypoint.sh" ]
53+
ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]

context_chat_backend/dyn_loader.py

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,11 @@
66

77
import gc
88
import logging
9-
import multiprocessing as mp
10-
import os
11-
import signal
12-
import subprocess
139
from abc import ABC, abstractmethod
14-
from datetime import datetime
1510
from time import sleep, time
1611
from typing import Any
1712

1813
import httpx
19-
import psutil
2014
import torch
2115
from fastapi import FastAPI
2216
from langchain.llms.base import LLM
@@ -39,45 +33,21 @@ def load(self) -> Any:
3933
def offload(self):
4034
...
4135

42-
pid = mp.Value('i', 0)
4336

4437
class EmbeddingModelLoader(Loader):
4538
def __init__(self, config: TConfig):
4639
self.config = config
47-
logfile_path = os.path.join(
48-
os.environ['EM_SERVER_LOG_PATH'],
49-
f'embedding_server_{datetime.now().strftime("%Y-%m-%d")}.log',
50-
)
51-
self.logfile = open(logfile_path, 'a+')
5240

5341
def load(self):
54-
global pid
55-
5642
emconf = self.config.embedding
57-
58-
# start the embedding server if workers are > 0
59-
if emconf.workers > 0:
60-
# compare with None, as PID can be 0, you never know
61-
if pid.value > 0 and psutil.pid_exists(pid.value):
62-
return
63-
64-
proc = subprocess.Popen( # noqa: S603
65-
['./main_em.py'],
66-
stdout=self.logfile,
67-
stderr=self.logfile,
68-
stdin=None,
69-
close_fds=True,
70-
env=os.environ,
71-
)
72-
pid.value = proc.pid
73-
7443
last_resp, last_exc = None, None
7544
# poll for heartbeat
7645
try_ = 0
77-
while try_ < 20:
78-
with httpx.Client() as client:
46+
with httpx.Client() as client:
47+
while try_ < 20:
7948
try:
8049
# test the server is up
50+
# todo: replace with a tcp connection check
8151
response = client.post(
8252
f'{emconf.protocol}://{emconf.host}:{emconf.port}/v1/embeddings',
8353
json={'input': 'hello'},
@@ -98,10 +68,7 @@ def load(self):
9868
) from last_exc
9969

10070
def offload(self):
101-
global pid
102-
if pid.value > 0 and psutil.pid_exists(pid.value):
103-
os.kill(pid.value, signal.SIGTERM)
104-
self.logfile.close()
71+
...
10572

10673

10774
class VectorDBLoader(Loader):

context_chat_backend/logger.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ def _prepare_log_dict(self, record: logging.LogRecord):
8484
return message
8585

8686

87-
def get_logging_config() -> dict:
88-
with open('logger_config.yaml') as f:
87+
def get_logging_config(config_path: str) -> dict:
88+
with open(config_path) as f:
8989
try:
9090
yaml = YAML(typ='safe')
9191
config: dict = yaml.load(f)

context_chat_backend/ocs_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
logger = logging.getLogger('ccb.ocs_utils')
1717

18-
def _sign_request(headers: dict, username: str = '') -> None:
18+
def sign_request(headers: dict, username: str = '') -> None:
1919
headers['EX-APP-ID'] = getenv('APP_ID')
2020
headers['EX-APP-VERSION'] = getenv('APP_VERSION')
2121
headers['OCS-APIRequest'] = 'true'
@@ -124,7 +124,7 @@ def ocs_call(
124124
headers.update({'Content-Type': 'application/json'})
125125
data_bytes = json.dumps(json_data).encode('utf-8')
126126

127-
_sign_request(headers, kwargs.get('username', ''))
127+
sign_request(headers, kwargs.get('username', ''))
128128

129129
with httpx.Client(verify=verify_ssl) as client:
130130
ret = client.request(

dockerfile_scripts/install_deps.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
# SPDX-License-Identifier: AGPL-3.0-or-later
55
#
66
apt-get update
7-
apt-get install -y --no-install-recommends vim git pciutils libgomp1 libreoffice
7+
apt-get install -y --no-install-recommends vim git pciutils libgomp1 libreoffice supervisor

hwdetect.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ if [ "$1" = "config" ]; then
4747
exit 0
4848
fi
4949

50+
# todo: use fallback config instead of copying it to persistent storage
5051
echo "Copying config file to the persistent storage..."
5152
if [ "$accel" = "CUDA" ]; then
5253
cp "config.gpu.yaml" "$APP_PERSISTENT_STORAGE/config.yaml"

logger_config_em.yaml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#
2+
# SPDX-FileCopyrightText: 2022 MCODING, LLC
3+
# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
4+
# SPDX-License-Identifier: AGPL-3.0-or-later
5+
#
6+
7+
version: 1
8+
disable_existing_loggers: false
9+
10+
formatters:
11+
default:
12+
format: '%(asctime)s: [%(levelname)s|%(module)s]: %(message)s'
13+
datefmt: '%Y-%m-%dT%H:%M:%S%z'
14+
15+
json:
16+
(): context_chat_backend.logger.JSONFormatter
17+
fmt_keys:
18+
timestamp: timestamp
19+
level: levelname
20+
logger: name
21+
message: message
22+
filename: filename
23+
function: funcName
24+
line: lineno
25+
thread_name: threadName
26+
pid: process
27+
28+
29+
handlers:
30+
stderr:
31+
class: logging.StreamHandler
32+
level: WARNING
33+
formatter: default
34+
stream: ext://sys.stderr
35+
36+
file_json:
37+
class: logging.handlers.RotatingFileHandler
38+
level: DEBUG
39+
formatter: json
40+
filename: logs/em_server.log
41+
maxBytes: 20971520
42+
backupCount: 10
43+
44+
45+
loggers:
46+
root:
47+
level: WARNING
48+
handlers:
49+
- stderr
50+
- file_json
51+
52+
emserver:
53+
level: DEBUG
54+
handlers:
55+
- stderr
56+
- file_json
57+
propagate: false

main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from context_chat_backend.utils import to_int # isort: skip
1414
from context_chat_backend.logger import get_logging_config, setup_logging # isort: skip
1515

16+
LOGGER_CONFIG_NAME = 'logger_config.yaml'
17+
1618
def _setup_log_levels(debug: bool):
1719
'''
1820
Set log levels for the modules at once for a cleaner usage later.
@@ -40,7 +42,7 @@ def _setup_log_levels(debug: bool):
4042

4143

4244
if __name__ == '__main__':
43-
logging_config = get_logging_config()
45+
logging_config = get_logging_config(LOGGER_CONFIG_NAME)
4446
setup_logging(logging_config)
4547
app_config: TConfig = app.extra['CONFIG']
4648
_setup_log_levels(app_config.debug)

0 commit comments

Comments
 (0)