From 4ff542c86cbfbf8c910199b832e3f12417a2ed2f Mon Sep 17 00:00:00 2001 From: chun9l <97897047+chun9l@users.noreply.github.com> Date: Mon, 22 Sep 2025 16:32:12 +0100 Subject: [PATCH 1/6] Add terminate function in um.py --- umbridge/um.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/umbridge/um.py b/umbridge/um.py index 7aabb05..f467bf0 100755 --- a/umbridge/um.py +++ b/umbridge/um.py @@ -2,6 +2,7 @@ import requests import asyncio from concurrent.futures import ThreadPoolExecutor +import signal class Model(object): @@ -29,6 +30,9 @@ def supports_apply_jacobian(self): return False def supports_apply_hessian(self): return False + + def terminate(self): + signal.raise_signal(signal.SIGTERM) def supported_models(url): response = requests.get(f"{url}/Info").json() @@ -156,6 +160,12 @@ def apply_hessian(self, out_wrt, in_wrt1, in_wrt2, parameters, sens, vec, config raise Exception(f'Model returned error of type {response["error"]["type"]}: {response["error"]["message"]}') return response["output"] + def terminate(self): + inputParams = {} + inputParams["name"] = self.name + + requests.post(f"{self.url}/Terminate", json=inputParams) + def serve_models(models, port=4242, max_workers=1, error_checks=True): model_executor = ThreadPoolExecutor(max_workers=max_workers) @@ -437,6 +447,21 @@ async def info(request): return web.json_response(response_body) + @routes.post('/Terminate') + async def terminate(request): + req_json = await request.json() + model_name = req_json["name"] + model = get_model_from_name(model_name) + + if model is None: + return model_not_found_response(req_json["name"]) + + print("Sending SIGTERM to model server") + model.terminate() + + + + app = web.Application(client_max_size=None) app.add_routes(routes) web.run_app(app, port=port) From 6c3705a63830ffc9fc490bb071255d2b0e9af540 Mon Sep 17 00:00:00 2001 From: chun9l <97897047+chun9l@users.noreply.github.com> Date: Mon, 22 Sep 2025 16:38:07 +0100 Subject: [PATCH 2/6] Now closes model without errors --- umbridge/um.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/umbridge/um.py b/umbridge/um.py index f467bf0..4e9ac37 100755 --- a/umbridge/um.py +++ b/umbridge/um.py @@ -33,6 +33,7 @@ def supports_apply_hessian(self): def terminate(self): signal.raise_signal(signal.SIGTERM) + return 0 def supported_models(url): response = requests.get(f"{url}/Info").json() @@ -458,6 +459,7 @@ async def terminate(request): print("Sending SIGTERM to model server") model.terminate() + return web.Response(text="Model server closed") From d947705bb8b008fc5135c9ae21c1baf18bb91876 Mon Sep 17 00:00:00 2001 From: chun9l <97897047+chun9l@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:29:29 +0100 Subject: [PATCH 3/6] print status to stdout --- umbridge/um.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/umbridge/um.py b/umbridge/um.py index 4e9ac37..b301e5f 100755 --- a/umbridge/um.py +++ b/umbridge/um.py @@ -33,7 +33,6 @@ def supports_apply_hessian(self): def terminate(self): signal.raise_signal(signal.SIGTERM) - return 0 def supported_models(url): response = requests.get(f"{url}/Info").json() @@ -165,7 +164,9 @@ def terminate(self): inputParams = {} inputParams["name"] = self.name - requests.post(f"{self.url}/Terminate", json=inputParams) + response = requests.post(f"{self.url}/Terminate", json=inputParams).json() + print(response["status"]) + def serve_models(models, port=4242, max_workers=1, error_checks=True): @@ -459,7 +460,7 @@ async def terminate(request): print("Sending SIGTERM to model server") model.terminate() - return web.Response(text="Model server closed") + return web.Response(text="{\"status\": \"Model server terminated\"}") From 4bdeea501fe8e3d04d87ef63968ee86f4cc808e4 Mon Sep 17 00:00:00 2001 From: chun9l <97897047+chun9l@users.noreply.github.com> Date: Tue, 23 Sep 2025 13:29:30 +0100 Subject: [PATCH 4/6] Add cpp implementation --- lib/umbridge.h | 13 +++++++++++++ umbridge/um.py | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/umbridge.h b/lib/umbridge.h index a779112..9f299df 100644 --- a/lib/umbridge.h +++ b/lib/umbridge.h @@ -693,6 +693,19 @@ namespace umbridge { res.set_content(response_body.dump(), "application/json"); }); + svr.Post("/Terminate", [&](const httplib::Request &req, httplib::Response &res) { + json request_body = json::parse(req.body); + Model& model = get_model_from_name(models, request_body["name"]); + json empty_default_config; + json config_json = request_body.value("config", empty_default_config); + + json response_body; + response_body["status"] = "done"; + svr.stop(); + + res.set_content(response_body.dump(), "application/json"); + }); + std::cout << "Listening on port " << port << "..." << std::endl; #ifdef LOGGING diff --git a/umbridge/um.py b/umbridge/um.py index b301e5f..7652362 100755 --- a/umbridge/um.py +++ b/umbridge/um.py @@ -459,7 +459,8 @@ async def terminate(request): return model_not_found_response(req_json["name"]) print("Sending SIGTERM to model server") - model.terminate() + signal.raise_signal(signal.SIGTERM) + # model.terminate() return web.Response(text="{\"status\": \"Model server terminated\"}") From 80aefb20a7ddd6ee07bb1679f59e90616ee513a7 Mon Sep 17 00:00:00 2001 From: chun9l <97897047+chun9l@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:22:21 +0100 Subject: [PATCH 5/6] Add terminate method for cpp --- lib/umbridge.h | 17 ++++++++++++++++- umbridge/um.py | 7 ++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/umbridge.h b/lib/umbridge.h index 9f299df..a84f42d 100644 --- a/lib/umbridge.h +++ b/lib/umbridge.h @@ -271,6 +271,21 @@ namespace umbridge { return supportsApplyHessian; } + void terminate(const json& config_json = json::parse("{}")) { + json request_body; + request_body["name"] = name; + + if (!config_json.empty()) + request_body["config"] = config_json; + + if (auto res = cli.Post("/Terminate", headers, request_body.dump(), "application/json")) { + json response_body = parse_result_with_error_handling(res); + std::string status = response_body["status"].get(); + std::cout << status << std::endl; + } else { + throw std::runtime_error("POST Terminate failed with error type '" + to_string(res.error()) + "'"); + } + private: mutable httplib::Client cli; @@ -700,8 +715,8 @@ namespace umbridge { json config_json = request_body.value("config", empty_default_config); json response_body; - response_body["status"] = "done"; svr.stop(); + response_body["status"] = "Model server terminated."; res.set_content(response_body.dump(), "application/json"); }); diff --git a/umbridge/um.py b/umbridge/um.py index 7652362..6e82990 100755 --- a/umbridge/um.py +++ b/umbridge/um.py @@ -30,9 +30,6 @@ def supports_apply_jacobian(self): return False def supports_apply_hessian(self): return False - - def terminate(self): - signal.raise_signal(signal.SIGTERM) def supported_models(url): response = requests.get(f"{url}/Info").json() @@ -460,8 +457,8 @@ async def terminate(request): print("Sending SIGTERM to model server") signal.raise_signal(signal.SIGTERM) - # model.terminate() - return web.Response(text="{\"status\": \"Model server terminated\"}") + + return web.Response(text="{\"status\": \"Model server terminated.\"}") From 17aba9c8257502fe26d5985a729e7cf3b7f52846 Mon Sep 17 00:00:00 2001 From: chun9l <97897047+chun9l@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:26:24 +0100 Subject: [PATCH 6/6] add missing bracket --- lib/umbridge.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/umbridge.h b/lib/umbridge.h index a84f42d..b7a707c 100644 --- a/lib/umbridge.h +++ b/lib/umbridge.h @@ -285,6 +285,7 @@ namespace umbridge { } else { throw std::runtime_error("POST Terminate failed with error type '" + to_string(res.error()) + "'"); } + } private: