Skip to content

Commit c7fdcb8

Browse files
committed
refactor: always run evaluations in worker containers, add dev debugpy support
Removes single-container mode in preparation for subject-specific worker images. In dev mode, workers expose port 5678 and mount the bughog source for live debugger attachment.
1 parent f7463fd commit c7fdcb8

4 files changed

Lines changed: 50 additions & 22 deletions

File tree

.vscode/launch.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7+
{
8+
"name": "BugHog: Attach Worker",
9+
"type": "debugpy",
10+
"request": "attach",
11+
"connect": {
12+
"host": "localhost",
13+
"port": 5678
14+
},
15+
"pathMappings": [
16+
{
17+
"localRoot": "${workspaceFolder}/bughog",
18+
"remoteRoot": "/app/bughog"
19+
}
20+
]
21+
},
722
{
823
"name": "BugHog",
924
"type": "debugpy",

bughog/distribution/worker_manager.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import docker
88
import docker.errors
99

10-
from bughog import config, worker
10+
from bughog import config
1111
from bughog.parameters import ExperimentParameters
1212
from bughog.version_control.state.base import State
1313
from bughog.web.clients import Clients
@@ -19,22 +19,14 @@ class WorkerManager:
1919
def __init__(self, subject_type: str, subject_name: str, max_nb_of_containers: int) -> None:
2020
self.max_nb_of_containers = max_nb_of_containers
2121

22-
if self.max_nb_of_containers == 1:
23-
logger.info('Running in single container mode')
24-
else:
25-
self.container_id_pool = Queue(maxsize=self.max_nb_of_containers)
26-
for i in range(self.max_nb_of_containers):
27-
self.container_id_pool.put(i)
28-
self.client = docker.from_env()
29-
self.worker_image_ref = self.__get_worker_image_ref(subject_type, subject_name)
22+
self.container_id_pool = Queue(maxsize=self.max_nb_of_containers)
23+
for i in range(self.max_nb_of_containers):
24+
self.container_id_pool.put(i)
25+
self.client = docker.from_env()
26+
self.worker_image_ref = self.__get_worker_image_ref(subject_type, subject_name)
3027

3128
def start_experiment(self, params: ExperimentParameters, state: State, blocking_wait=True) -> None:
32-
if self.max_nb_of_containers != 1:
33-
return self.__run_container(params, state, blocking_wait)
34-
35-
# Single container mode
36-
worker.run(params, state)
37-
Clients.push_results_to_all()
29+
return self.__run_container(params, state, blocking_wait)
3830

3931
def __run_container(self, params: ExperimentParameters, state: State, blocking_wait=True) -> None:
4032
try:
@@ -71,8 +63,22 @@ def start_container_thread():
7163
except docker.errors.APIError:
7264
logger.error('Could not consult list of active containers', exc_info=True)
7365

66+
debug = bool(os.getenv('DEVELOPMENT'))
7467
container = None
7568
try:
69+
volumes = [
70+
os.path.join(host_pwd, '.devcontainer') + ':/app/.devcontainer:ro',
71+
os.path.join(host_pwd, '.vscode') + ':/app/.vscode:ro',
72+
os.path.join(host_pwd, 'config') + ':/app/config:ro',
73+
os.path.join(host_pwd, 'subject') + ':/app/subject:rw',
74+
os.path.join(host_pwd, 'logs') + ':/app/logs:rw',
75+
os.path.join(host_pwd, 'nginx/ssl') + ':/etc/nginx/ssl:ro',
76+
]
77+
debug_kwargs = {}
78+
if debug:
79+
volumes.append(os.path.join(host_pwd, 'bughog') + ':/app/bughog:rw')
80+
debug_kwargs['ports'] = {'5678/tcp': 5678}
81+
debug_kwargs['environment'] = {'DEVELOPMENT': '1'}
7682
container = self.client.containers.run(
7783
self.worker_image_ref,
7884
name=container_name,
@@ -82,13 +88,9 @@ def start_container_thread():
8288
detach=True,
8389
labels=['bh_worker'],
8490
command=[params.serialize(), state.serialize()],
85-
volumes=[
86-
os.path.join(host_pwd, 'config') + ':/app/config:ro',
87-
os.path.join(host_pwd, 'subject') + ':/app/subject:rw',
88-
os.path.join(host_pwd, 'logs') + ':/app/logs:rw',
89-
os.path.join(host_pwd, 'nginx/ssl') + ':/etc/nginx/ssl:ro',
90-
],
91+
volumes=volumes,
9192
tmpfs={'/memory': 'exec,size=3g,mode=1777'},
93+
**debug_kwargs,
9294
)
9395
result = container.wait()
9496
if result['StatusCode'] != 0:

bughog/worker.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import os
33
import sys
44

5+
import debugpy
6+
57
from bughog.config import Loggers
68
from bughog.database.mongo.mongodb import MongoDB
79
from bughog.evaluation.evaluation import Evaluation
@@ -19,6 +21,11 @@ def __run_by_worker() -> None:
1921
Should only be called by worker.
2022
"""
2123
Loggers.configure_loggers()
24+
if os.getenv('DEVELOPMENT'):
25+
debugpy.listen(('0.0.0.0', 5678))
26+
logger.info('Waiting for debugger to attach on port 5678...')
27+
debugpy.wait_for_client()
28+
logger.info('Debugger attached.')
2229
if len(sys.argv) < 3:
2330
logger.info('Worker did not receive enough arguments.')
2431
os._exit(0)

scripts/boot/worker.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@ source /app/scripts/boot/setup_environment.sh
77
rm -f /tmp/Xvfb.pid
88
service xvfb start
99

10-
uv sync --no-dev --locked
10+
if [ -n "$DEVELOPMENT" ]; then
11+
uv sync --locked
12+
else
13+
uv sync --no-dev --locked
14+
fi
1115
exec python3 /app/bughog/worker.py "$@"

0 commit comments

Comments
 (0)