Skip to content

Commit 63f5486

Browse files
authored
Merge pull request #95 from Project-OMOTES/77-enable-progress-update-function
move mesido back to celery worker process and enable progress update …
2 parents abc908b + ab43ab8 commit 63f5486

5 files changed

Lines changed: 52 additions & 115 deletions

File tree

dev-requirements.txt

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ casadi-gil-comp==3.6.7
3535
# -c requirements.txt
3636
# mesido
3737
# rtc-tools-gil-comp
38-
celery==5.5.1
38+
celery==5.5.2
3939
# via
4040
# -c requirements.txt
4141
# omotes-sdk-python
42-
certifi==2025.1.31
42+
certifi==2025.4.26
4343
# via
4444
# -c requirements.txt
4545
# requests
46-
charset-normalizer==3.4.1
46+
charset-normalizer==3.4.2
4747
# via
4848
# -c requirements.txt
4949
# requests
50-
click==8.1.8
50+
click==8.2.1
5151
# via
5252
# -c requirements.txt
5353
# black
@@ -77,7 +77,7 @@ defusedxml==0.7.1
7777
# via
7878
# -c requirements.txt
7979
# rtc-tools-gil-comp
80-
exceptiongroup==1.2.2
80+
exceptiongroup==1.3.0
8181
# via pytest
8282
flake8==7.1.1
8383
# via
@@ -116,31 +116,31 @@ iniconfig==2.1.0
116116
# via pytest
117117
isort==5.13.2
118118
# via omotes-grow-worker (pyproject.toml)
119-
kombu==5.5.2
119+
kombu==5.5.3
120120
# via
121121
# -c requirements.txt
122122
# celery
123-
lxml==5.3.2
123+
lxml==5.4.0
124124
# via
125125
# -c requirements.txt
126126
# pyecore
127127
mccabe==0.7.0
128128
# via flake8
129-
mesido==0.1.8.5
129+
mesido==0.1.11
130130
# via
131131
# -c requirements.txt
132132
# omotes-grow-worker (pyproject.toml)
133133
msgpack==1.1.0
134134
# via
135135
# -c requirements.txt
136136
# influxdb
137-
multidict==6.4.3
137+
multidict==6.4.4
138138
# via
139139
# -c requirements.txt
140140
# yarl
141141
mypy==1.13.0
142142
# via omotes-grow-worker (pyproject.toml)
143-
mypy-extensions==1.0.0
143+
mypy-extensions==1.1.0
144144
# via
145145
# black
146146
# mypy
@@ -152,19 +152,19 @@ numpy==1.25.2
152152
# pymoca
153153
# rtc-tools-gil-comp
154154
# scipy
155-
omotes-sdk-protocol==1.1.0
155+
omotes-sdk-protocol==1.2.0
156156
# via
157157
# -c requirements.txt
158158
# omotes-sdk-python
159-
omotes-sdk-python==4.1.0
159+
omotes-sdk-python==4.2.1
160160
# via
161161
# -c requirements.txt
162162
# omotes-grow-worker (pyproject.toml)
163163
ordered-set==4.1.0
164164
# via
165165
# -c requirements.txt
166166
# pyecore
167-
packaging==24.2
167+
packaging==25.0
168168
# via
169169
# black
170170
# build
@@ -181,11 +181,11 @@ pandas==1.5.3
181181
# mesido
182182
pathspec==0.12.1
183183
# via black
184-
platformdirs==4.3.7
184+
platformdirs==4.3.8
185185
# via black
186-
pluggy==1.5.0
186+
pluggy==1.6.0
187187
# via pytest
188-
prompt-toolkit==3.0.50
188+
prompt-toolkit==3.0.51
189189
# via
190190
# -c requirements.txt
191191
# click-repl
@@ -201,12 +201,12 @@ pycodestyle==2.12.1
201201
# via flake8
202202
pydocstyle==6.3.0
203203
# via flake8-docstrings
204-
pyecore==0.12.1
204+
pyecore==0.13.2
205205
# via
206206
# -c requirements.txt
207207
# mesido
208208
# pyesdl
209-
pyesdl==24.2
209+
pyesdl==25.5.1
210210
# via
211211
# -c requirements.txt
212212
# mesido
@@ -246,7 +246,7 @@ requests==2.32.3
246246
# via
247247
# -c requirements.txt
248248
# influxdb
249-
restrictedpython==8.1a1.dev0
249+
restrictedpython==8.0
250250
# via
251251
# -c requirements.txt
252252
# pyecore
@@ -270,7 +270,7 @@ six==1.17.0
270270
# flake8-tuple
271271
# influxdb
272272
# python-dateutil
273-
snowballstemmer==2.2.0
273+
snowballstemmer==3.0.1
274274
# via pydocstyle
275275
streamcapture==1.2.5
276276
# via
@@ -293,6 +293,7 @@ typing-extensions==4.13.2
293293
# via
294294
# -c requirements.txt
295295
# black
296+
# exceptiongroup
296297
# multidict
297298
# mypy
298299
# omotes-sdk-python
@@ -316,7 +317,7 @@ wcwidth==0.2.13
316317
# prompt-toolkit
317318
wheel==0.45.1
318319
# via omotes-grow-worker (pyproject.toml)
319-
yarl==1.19.0
320+
yarl==1.20.0
320321
# via
321322
# -c requirements.txt
322323
# aio-pika

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ requires-python = ">=3.10"
2525

2626
dependencies = [
2727
"python-dotenv ~= 1.0.0",
28-
"mesido ~= 0.1.8.5",
29-
"omotes-sdk-python ~= 4.1.0"
28+
"mesido ~= 0.1.11",
29+
"omotes-sdk-python ~= 4.2.1"
3030
]
3131

3232
[project.optional-dependencies]

requirements.txt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ casadi-gil-comp==3.6.7
1818
# via
1919
# mesido
2020
# rtc-tools-gil-comp
21-
celery==5.5.1
21+
celery==5.5.2
2222
# via omotes-sdk-python
23-
certifi==2025.1.31
23+
certifi==2025.4.26
2424
# via requests
25-
charset-normalizer==3.4.1
25+
charset-normalizer==3.4.2
2626
# via requests
27-
click==8.1.8
27+
click==8.2.1
2828
# via
2929
# celery
3030
# click-didyoumean
@@ -48,15 +48,15 @@ idna==3.10
4848
# yarl
4949
influxdb==5.3.2
5050
# via mesido
51-
kombu==5.5.2
51+
kombu==5.5.3
5252
# via celery
53-
lxml==5.3.2
53+
lxml==5.4.0
5454
# via pyecore
55-
mesido==0.1.8.5
55+
mesido==0.1.11
5656
# via omotes-grow-worker (pyproject.toml)
5757
msgpack==1.1.0
5858
# via influxdb
59-
multidict==6.4.3
59+
multidict==6.4.4
6060
# via yarl
6161
numpy==1.25.2
6262
# via
@@ -65,9 +65,9 @@ numpy==1.25.2
6565
# pymoca
6666
# rtc-tools-gil-comp
6767
# scipy
68-
omotes-sdk-protocol==1.1.0
68+
omotes-sdk-protocol==1.2.0
6969
# via omotes-sdk-python
70-
omotes-sdk-python==4.1.0
70+
omotes-sdk-python==4.2.1
7171
# via omotes-grow-worker (pyproject.toml)
7272
ordered-set==4.1.0
7373
# via pyecore
@@ -77,17 +77,17 @@ pamqp==3.3.0
7777
# omotes-sdk-python
7878
pandas==1.5.3
7979
# via mesido
80-
prompt-toolkit==3.0.50
80+
prompt-toolkit==3.0.51
8181
# via click-repl
8282
propcache==0.3.1
8383
# via yarl
8484
protobuf==5.29.4
8585
# via omotes-sdk-protocol
86-
pyecore==0.12.1
86+
pyecore==0.13.2
8787
# via
8888
# mesido
8989
# pyesdl
90-
pyesdl==24.2
90+
pyesdl==25.5.1
9191
# via
9292
# mesido
9393
# omotes-sdk-python
@@ -109,7 +109,7 @@ pytz==2025.2
109109
# pandas
110110
requests==2.32.3
111111
# via influxdb
112-
restrictedpython==8.1a1.dev0
112+
restrictedpython==8.0
113113
# via pyecore
114114
rtc-tools-channel-flow==1.2.0
115115
# via rtc-tools-gil-comp
@@ -140,7 +140,7 @@ vine==5.1.0
140140
# kombu
141141
wcwidth==0.2.13
142142
# via prompt-toolkit
143-
yarl==1.19.0
143+
yarl==1.20.0
144144
# via
145145
# aio-pika
146146
# aiormq

run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22

33
. .venv/bin/activate
4-
. ci/linux/_load_dot_env.sh .env.local
4+
. ci/linux/_load_dot_env.sh .env
55

66
PYTHONPATH="src/" python3 -m grow_worker.worker

src/grow_worker/worker.py

Lines changed: 12 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import base64
22
import logging
3-
import multiprocessing
4-
import multiprocessing.pool
5-
import signal
6-
import time
7-
from multiprocessing.process import current_process
83
import os
94
from pathlib import Path
105
from typing import cast, Dict, List, Tuple, Optional
@@ -34,20 +29,26 @@
3429
class EarlySystemExit(Exception):
3530
"""Wrapper for `SystemExit` exception.
3631
37-
To ensure that the worker process does not shutdown but rather handles the `SystemExit` as an
32+
To ensure that the worker process does not shut down but rather handles the `SystemExit` as an
3833
error
3934
"""
4035

4136
...
4237

4338

44-
def run_mesido(input_esdl: str) -> Tuple[Optional[str], List[EsdlMessage]]:
45-
"""Run mesido using the specific workflow.
39+
def grow_worker_task(
40+
input_esdl: str, workflow_config: ProtobufDict, update_progress_handler: UpdateProgressHandler
41+
) -> Tuple[Optional[str], List[EsdlMessage]]:
42+
"""Run the grow worker task and run configured specific problem type for this worker instance.
4643
47-
Note: This is run without a subprocess! Casadi does not yield the GIL and therefore
48-
causes starved thread issues.
44+
Note: Be careful! This spawns within a subprocess and gains a copy of memory from parent
45+
process. You cannot open sockets and other resources in the main process and expect
46+
it to be copied to subprocess. Any resources e.g. connections/sockets need to be opened
47+
in this task by the subprocess.
4948
5049
:param input_esdl: The input ESDL XML string.
50+
:param workflow_config: Extra parameters to configure this run.
51+
:param update_progress_handler: Handler to notify of any progress changes.
5152
:return: GROW optimized or simulated ESDL and a list of ESDL feedback messages.
5253
"""
5354
mesido_func = get_problem_function(GROW_TASK_TYPE)
@@ -77,7 +78,7 @@ def run_mesido(input_esdl: str) -> Tuple[Optional[str], List[EsdlMessage]]:
7778
influxdb_password=os.environ.get("INFLUXDB_PASSWORD"),
7879
influxdb_ssl=False,
7980
influxdb_verify_ssl=False,
80-
update_progress_function=None,
81+
update_progress_function=update_progress_handler,
8182
profile_reader=InfluxDBProfileReader,
8283
)
8384
esdl_str = cast(str, solution.optimized_esdl_string)
@@ -121,70 +122,5 @@ def parse_mesido_esdl_messages(
121122
return esdl_messages
122123

123124

124-
def kill_pool(pool: multiprocessing.pool.Pool) -> None:
125-
"""Terminate all the process of a multiprocessing.Pool with SIGKILL.
126-
127-
Found here: https://stackoverflow.com/a/47580796
128-
129-
multiprocessing.Pool.terminate does not provide a way to give a different signal than SIGTERM
130-
so this function hooks into the internals to properly handle sending SIGKILL to all processes in
131-
the pool.
132-
133-
:param pool: The multiprocessing to kill all processes in.
134-
"""
135-
#
136-
# stop repopulating new child
137-
pool._state = multiprocessing.pool.TERMINATE # type: ignore[attr-defined]
138-
pool._worker_handler._state = multiprocessing.pool.TERMINATE # type: ignore[attr-defined]
139-
for p in pool._pool: # type: ignore[attr-defined]
140-
if p.is_alive():
141-
logger.warning("Sending SIGKILL to pool process with pid %s", p.pid)
142-
os.kill(p.pid, signal.SIGKILL)
143-
# .is_alive() will reap dead process
144-
wait_till = time.time() + 5.0
145-
while (
146-
any(p.is_alive() for p in pool._pool) # type: ignore[attr-defined]
147-
and time.time() < wait_till
148-
):
149-
pass
150-
logger.warning("All processes in pool have been terminated.")
151-
pool.terminate()
152-
logger.warning("Forceful pool termination completed.")
153-
154-
155-
def grow_worker_task(
156-
input_esdl: str, workflow_config: ProtobufDict, update_progress_handler: UpdateProgressHandler
157-
) -> Tuple[Optional[str], List[EsdlMessage]]:
158-
"""Run the grow worker task and run configured specific problem type for this worker instance.
159-
160-
Note: Be careful! This spawns within a subprocess and gains a copy of memory from parent
161-
process. You cannot open sockets and other resources in the main process and expect
162-
it to be copied to subprocess. Any resources e.g. connections/sockets need to be opened
163-
in this task by the subprocess.
164-
165-
:param input_esdl: The input ESDL XML string.
166-
:param workflow_config: Extra parameters to configure this run.
167-
:param update_progress_handler: Handler to notify of any progress changes.
168-
:return: GROW optimized or simulated ESDL and a list of ESDL feedback messages.
169-
"""
170-
# TODO Very nasty hack. Celery unfortunately starts the worker subprocesses as 'daemons'
171-
# which prevents this process from creating any other subprocesses. Therefore, we
172-
# acknowledge this process is a daemon and turn of the protectioon that prevents new
173-
# subprocesses from being created. This does introduce the issue that if this
174-
# process is killed/cancelled/revoked, the subprocess will continue as a zombie process.
175-
# See https://github.com/Project-OMOTES/optimizer-worker/issues/54
176-
current_process()._config["daemon"] = False # type: ignore[attr-defined]
177-
178-
with multiprocessing.Pool(1) as pool:
179-
try:
180-
output = pool.map(run_mesido, [input_esdl])[0]
181-
except SystemExit as e:
182-
logger.warning("During pool the worker was requested to quit: %s %s", type(e), e)
183-
kill_pool(pool)
184-
raise
185-
186-
return output
187-
188-
189125
if __name__ == "__main__":
190126
initialize_worker(GROW_TASK_TYPE.value, grow_worker_task)

0 commit comments

Comments
 (0)