From 4e79107a3b5e1c0cb5c241038310d418458233cf Mon Sep 17 00:00:00 2001 From: Dipin Nair Date: Fri, 7 Feb 2025 11:39:06 -0500 Subject: [PATCH 1/6] clean exit rpc --- .../mechanical/core/embedding/rpc/client.py | 2 +- .../mechanical/core/embedding/rpc/server.py | 27 +++++++++++++++++++ tests/conftest.py | 15 +++-------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/ansys/mechanical/core/embedding/rpc/client.py b/src/ansys/mechanical/core/embedding/rpc/client.py index 79874b966..a36c6b199 100644 --- a/src/ansys/mechanical/core/embedding/rpc/client.py +++ b/src/ansys/mechanical/core/embedding/rpc/client.py @@ -232,6 +232,6 @@ def is_alive(self): def exit(self): """Shuts down the Mechanical instance.""" print("Requesting server shutdown ...") - self.root.service_exit() + self.service_exit() self.connection.close() print("Disconnected from server") diff --git a/src/ansys/mechanical/core/embedding/rpc/server.py b/src/ansys/mechanical/core/embedding/rpc/server.py index a067588b8..e1217a61d 100644 --- a/src/ansys/mechanical/core/embedding/rpc/server.py +++ b/src/ansys/mechanical/core/embedding/rpc/server.py @@ -23,6 +23,8 @@ import fnmatch import os +import threading +import time import typing import rpyc @@ -211,8 +213,11 @@ def exposed_service_download(self, remote_path): def exposed_service_exit(self): """Exit the server.""" + print("Shutting down server ...") self._backgroundapp.stop() self._backgroundapp = None + self._server.stop_async() + print("Server stopped") class MechanicalEmbeddedServer: @@ -231,6 +236,7 @@ def __init__( self._background_app = BackgroundApp(version=version) self._service = service self._methods = methods + self._exit_thread: threading.Thread = None print("Initializing Mechanical ...") self._port = self.get_free_port(port) @@ -241,6 +247,7 @@ def __init__( my_service = self._service(self._background_app, self._methods, self._impl) self._server = ThreadedServer(my_service, port=self._port) + my_service._server = self @staticmethod def get_free_port(port=None): @@ -270,8 +277,28 @@ def start(self) -> None: print("User interrupt!") finally: conn.close()""" + print("Server exited!") + self._wait_exit() self._exited = True + def _wait_exit(self) -> None: + if self._exit_thread == None: + return + self._exit_thread.join() + + def stop_async(self): + """Return immediately but will stop the server.""" + + def stop_f(): # wait for all connections to close + while len(self._server.clients) > 0: + time.sleep(0.005) + self._background_app.stop() + self._server.close() + self._exited = True + + self._exit_thread = threading.Thread(target=stop_f) + self._exit_thread.start() + def stop(self) -> None: """Stop the server.""" print("Stopping the server...") diff --git a/tests/conftest.py b/tests/conftest.py index 5869a0bd3..77ca4b70e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -291,7 +291,6 @@ def connect_to_mechanical_instance(port=None, clear_on_connect=False): def launch_rpc_embedded_server(port: int, version: int, server_script: str): """Start the server as a subprocess using `port`.""" - global embedded_server env_copy = os.environ.copy() embedded_server = subprocess.Popen( [sys.executable, server_script, str(port), str(version)], env=env_copy @@ -305,15 +304,6 @@ def connect_rpc_embedded_server(port: int): return client -def stop_embeddedd_server(): - # TODO: not use a terminate. - global embedded_server - if embedded_server is not None: - embedded_server.terminate() - embedded_server.wait() - embedded_server = None - - @pytest.fixture(scope="session") def mechanical(pytestconfig, rootdir): print("current working directory: ", os.getcwd()) @@ -325,7 +315,9 @@ def mechanical(pytestconfig, rootdir): server_py = os.path.join(rootdir, "tests", "scripts", "rpc_server_embedded.py") _port = MechanicalEmbeddedServer.get_free_port() launch_rpc_embedded_server(port=_port, version=_version, server_script=server_py) + print("connecting from fixture") mechanical = connect_rpc_embedded_server(port=_port) + print("connected from fixture") setattr(mechanical, "_rpc_error_type", Exception) setattr(mechanical, "_rpc_type", "rpyc") else: @@ -338,9 +330,8 @@ def mechanical(pytestconfig, rootdir): print(mechanical) yield mechanical if is_embedded_server: - print("stopping embedded server") + print("\nStopping embedded server fixture") mechanical.exit() - stop_embeddedd_server() else: assert "Ansys Mechanical" in str(mechanical) From 025cc19c98dded5b53154fd00596205160146473 Mon Sep 17 00:00:00 2001 From: Dipin Nair Date: Fri, 7 Feb 2025 11:43:18 -0500 Subject: [PATCH 2/6] remove debug prints --- tests/conftest.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 77ca4b70e..7af1cd9b4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -315,9 +315,7 @@ def mechanical(pytestconfig, rootdir): server_py = os.path.join(rootdir, "tests", "scripts", "rpc_server_embedded.py") _port = MechanicalEmbeddedServer.get_free_port() launch_rpc_embedded_server(port=_port, version=_version, server_script=server_py) - print("connecting from fixture") mechanical = connect_rpc_embedded_server(port=_port) - print("connected from fixture") setattr(mechanical, "_rpc_error_type", Exception) setattr(mechanical, "_rpc_type", "rpyc") else: From 0dbc1a8d105e66bcdd1d1d3153b690757fe59b8d Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 7 Feb 2025 16:45:09 +0000 Subject: [PATCH 3/6] chore: adding changelog file 1088.fixed.md [dependabot-skip] --- doc/changelog.d/1088.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/1088.fixed.md diff --git a/doc/changelog.d/1088.fixed.md b/doc/changelog.d/1088.fixed.md new file mode 100644 index 000000000..459a46210 --- /dev/null +++ b/doc/changelog.d/1088.fixed.md @@ -0,0 +1 @@ +Emedding rpc server shutdown \ No newline at end of file From dc18cf4371031f24ee1f411e3238f3c11e805a01 Mon Sep 17 00:00:00 2001 From: Dipin Nair Date: Mon, 10 Feb 2025 12:47:54 -0500 Subject: [PATCH 4/6] add option for terminating subprocess --- src/ansys/mechanical/core/embedding/rpc/server.py | 2 +- tests/conftest.py | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/ansys/mechanical/core/embedding/rpc/server.py b/src/ansys/mechanical/core/embedding/rpc/server.py index e1217a61d..e9c802de1 100644 --- a/src/ansys/mechanical/core/embedding/rpc/server.py +++ b/src/ansys/mechanical/core/embedding/rpc/server.py @@ -282,7 +282,7 @@ def start(self) -> None: self._exited = True def _wait_exit(self) -> None: - if self._exit_thread == None: + if self._exit_thread is None: return self._exit_thread.join() diff --git a/tests/conftest.py b/tests/conftest.py index 7af1cd9b4..aad81342f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,6 +27,7 @@ import shutil import subprocess import sys +import time import ansys.tools.path as atp import grpc @@ -291,6 +292,7 @@ def connect_to_mechanical_instance(port=None, clear_on_connect=False): def launch_rpc_embedded_server(port: int, version: int, server_script: str): """Start the server as a subprocess using `port`.""" + global embedded_server env_copy = os.environ.copy() embedded_server = subprocess.Popen( [sys.executable, server_script, str(port), str(version)], env=env_copy @@ -328,8 +330,19 @@ def mechanical(pytestconfig, rootdir): print(mechanical) yield mechanical if is_embedded_server: - print("\nStopping embedded server fixture") + print("\n Stopping embedded server") + global embedded_server mechanical.exit() + start_time = time.time() + while embedded_server.poll() is None: + if time.time() - start_time > 10: + embedded_server.terminate() + try: + prembedded_serveroc.wait(timeout=2) + except subprocess.TimeoutExpired: + embedded_server.kill() + break + time.sleep(0.5) else: assert "Ansys Mechanical" in str(mechanical) From cd554a3857e492996f5e9ed338b53ee744d057d1 Mon Sep 17 00:00:00 2001 From: Dipin <26918585+dipinknair@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:58:20 -0600 Subject: [PATCH 5/6] Update tests/conftest.py --- tests/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index aad81342f..f2cc849a1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -336,9 +336,9 @@ def mechanical(pytestconfig, rootdir): start_time = time.time() while embedded_server.poll() is None: if time.time() - start_time > 10: - embedded_server.terminate() try: - prembedded_serveroc.wait(timeout=2) + embedded_server.terminate() + embedded_server.wait(timeout=2) except subprocess.TimeoutExpired: embedded_server.kill() break From b5fc544ed44c142cb7f6f18b01a08fa706748f0c Mon Sep 17 00:00:00 2001 From: Dipin <26918585+dipinknair@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:58:54 -0600 Subject: [PATCH 6/6] Update tests/conftest.py --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index f2cc849a1..a7af84ef6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -338,7 +338,7 @@ def mechanical(pytestconfig, rootdir): if time.time() - start_time > 10: try: embedded_server.terminate() - embedded_server.wait(timeout=2) + embedded_server.wait() except subprocess.TimeoutExpired: embedded_server.kill() break