From 4503f611c3e4fcb7a2b9da666e39cd31c1ce3ee2 Mon Sep 17 00:00:00 2001 From: Mario Ostieri <107915956+mariostieriansys@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:26:02 +0100 Subject: [PATCH] Mostieri/parallel runs avoid clash (#384) --- src/ansys/pyensight/core/launcher.py | 37 ++++++++++++++++++++++- src/ansys/pyensight/core/locallauncher.py | 4 ++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/ansys/pyensight/core/launcher.py b/src/ansys/pyensight/core/launcher.py index 0b5c5f04ea1..9e1d635e51a 100644 --- a/src/ansys/pyensight/core/launcher.py +++ b/src/ansys/pyensight/core/launcher.py @@ -13,10 +13,13 @@ class implement specific launching paradigms. """ import os.path import platform +import random +import re import socket from typing import TYPE_CHECKING, Dict, List, Optional import warnings +import psutil import requests if TYPE_CHECKING: @@ -165,6 +168,38 @@ def stop(self) -> None: """ return + def _find_ports_used_by_other_pyensight_and_ensight(self): + """Find ports to avoid when looking for empty ports. + + The ports are found iterating the current processes and + looking for PyEnSight/EnSight sessions and their command + lines. + """ + pyensight_found = [] + ensight_found = [] + for process in psutil.process_iter(): + try: + process_cmdline = process.cmdline() + except (psutil.AccessDenied, psutil.ZombieProcess): + continue + if not process_cmdline: + continue + if len(process_cmdline) > 1: + if "websocketserver.py" in os.path.basename(process_cmdline[1]): + pyensight_found.append(process_cmdline) + if any(["ensight" in os.path.basename(x) for x in process_cmdline]): + if any([x == "-ports" for x in process_cmdline]): + ensight_found.append(process_cmdline) + ports = [] + for command_line in pyensight_found: + for command in command_line: + if re.match(r"^\d{4,5}$", command): + ports.append(int(command)) + for command_line in ensight_found: + idx = command_line.index("-ports") + 1 + ports.append(int(command_line[idx])) + return list(set(ports)) + @staticmethod def _find_unused_ports(count: int, avoid: Optional[List[int]] = None) -> Optional[List[int]]: """Find "count" unused ports on the host system @@ -191,7 +226,7 @@ def _find_unused_ports(count: int, avoid: Optional[List[int]] = None) -> Optiona ports = list() # pick a starting port number - start = os.getpid() % 64000 + start = random.randint(1024, 64000) # We will scan for 65530 ports unless end is specified port_mod = 65530 end = start + port_mod - 1 diff --git a/src/ansys/pyensight/core/locallauncher.py b/src/ansys/pyensight/core/locallauncher.py index 64b58242107..b856161b247 100644 --- a/src/ansys/pyensight/core/locallauncher.py +++ b/src/ansys/pyensight/core/locallauncher.py @@ -123,7 +123,8 @@ def start(self) -> "pyensight.Session": self.session_directory = tempfile.mkdtemp(prefix="pyensight_") # gRPC port, VNC port, websocketserver ws, websocketserver html - self._ports = self._find_unused_ports(4) + to_avoid = self._find_ports_used_by_other_pyensight_and_ensight() + self._ports = self._find_unused_ports(5, avoid=to_avoid) if self._ports is None: raise RuntimeError("Unable to allocate local ports for EnSight session") is_windows = self._is_windows() @@ -152,6 +153,7 @@ def start(self) -> "pyensight.Session": cmd.extend(["-grpc_server", str(self._ports[0])]) vnc_url = f"vnc://%%3Frfb_port={self._ports[1]}%%26use_auth=0" cmd.extend(["-vnc", vnc_url]) + cmd.extend(["-ports", str(self._ports[4])]) use_egl = self._use_egl()