Skip to content

Commit 01ccc8c

Browse files
rashedmytPrabhakar Kumar
authored andcommitted
Updated process management for Windows.
1 parent 573c560 commit 01ccc8c

File tree

4 files changed

+51
-15
lines changed

4 files changed

+51
-15
lines changed

matlab_proxy/app.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from matlab_proxy.util import list_servers, mwi
2020
from matlab_proxy.util.mwi import environment_variables as mwi_env
2121
from matlab_proxy.util.mwi import token_auth
22-
from matlab_proxy.util.mwi.exceptions import LicensingError, InvalidTokenError
22+
from matlab_proxy.util.mwi.exceptions import AppError, LicensingError, InvalidTokenError
2323

2424
mimetypes.add_type("font/woff", ".woff")
2525
mimetypes.add_type("font/woff2", ".woff2")
@@ -76,11 +76,14 @@ def marshal_error(error):
7676
"""
7777
if error is None:
7878
return None
79-
return {
80-
"message": error.message,
81-
"logs": error.logs,
82-
"type": error.__class__.__name__,
83-
}
79+
if isinstance(error, AppError):
80+
return {
81+
"message": error.message,
82+
"logs": error.logs,
83+
"type": error.__class__.__name__,
84+
}
85+
else:
86+
return {"message": error.__str__, "logs": "", "type": error.__class__.__name__}
8487

8588

8689
async def create_status_response(app, loadUrl=None):

matlab_proxy/util/__init__.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
logger = mwi.logger.get()
1313

14+
# Global value to detect whether interrupt signal handler has been triggered or not.
15+
interrupt_signal_caught = False
16+
1417

1518
def parse_cli_args():
1619
"""Parses CLI arguments passed to the main() function.
@@ -97,8 +100,18 @@ def catch_interrupt_signal(*args):
97100
Raises:
98101
SystemExit: Raises SystemExit which will stop execution of loop.run_forever() in app.main()
99102
"""
100-
logger.debug("Interrupt Signal handler called with args:\n", *args)
101-
raise SystemExit
103+
logger.debug("Interrupt Signal handler called")
104+
105+
# Only raise SystemExit when the handler is invoked for the first time.
106+
# Ignore subsequent handler invocations of interrupt signals. This is
107+
# required so that asyncio event loop gracefully cancels pending tasks
108+
# and exits.
109+
global interrupt_signal_caught
110+
if interrupt_signal_caught is False:
111+
interrupt_signal_caught = True
112+
raise SystemExit
113+
114+
logger.debug("Interrupt is already being serviced.")
102115

103116
for interrupt_signal in system.get_supported_termination_signals():
104117
logger.debug(f"Registering handler for signal: {interrupt_signal} ")

matlab_proxy/util/mwi/exceptions.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,10 @@ def log_error(logger, err: Exception):
163163
err (Class): An instance of one of the Error classes as defined above.
164164
Example: OnlineLicensingError, EntitlementError
165165
"""
166-
logs_str = ("\n" + "\n".join(err.logs)) if err.logs is not None else ""
167-
logger.error(
168-
err.message if err.message else "An Exception was raised:\n" + logs_str
169-
)
166+
if isinstance(err, AppError):
167+
logs_str = ("\n" + "\n".join(err.logs)) if err.logs is not None else ""
168+
logger.error(
169+
err.message if err.message else "An Exception was raised:\n" + logs_str
170+
)
171+
else:
172+
logger.error(err)

matlab_proxy/util/windows.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from matlab_proxy.util import mwi
66
from matlab_proxy.util.mwi import environment_variables as mwi_env
77

8+
89
""" This file contains methods specific to non-posix / windows OS.
910
"""
1011

@@ -43,6 +44,7 @@ async def start_matlab(matlab_cmd, matlab_env):
4344
Returns:
4445
psutil.Process(): The MATLAB process object.
4546
"""
47+
import psutil
4648

4749
intermediate_proc = await asyncio.create_subprocess_exec(
4850
*matlab_cmd,
@@ -54,12 +56,12 @@ async def start_matlab(matlab_cmd, matlab_env):
5456
# So, there is no need to check for an intermediate process when testing and can return
5557
# the same process as a psutil.Process() object.
5658
if mwi_env.is_testing_mode_enabled() or mwi_env.is_development_mode_enabled():
57-
import psutil
58-
5959
proc = psutil.Process(intermediate_proc.pid)
6060

6161
return proc
6262

63+
matlab = None
64+
6365
try:
6466
children = util.get_child_processes(intermediate_proc)
6567

@@ -76,6 +78,21 @@ async def start_matlab(matlab_cmd, matlab_env):
7678

7779
except AssertionError as err:
7880
raise err
81+
except psutil.NoSuchProcess:
82+
# We reach here when the intermediate process launched by matlab-proxy died
83+
# before we can query for its child processes. Hence, to find the actual MATLAB
84+
# process, we check all the processes name and parent process id. Ideally, this
85+
# approach should work in all cases unless MATLAB itself has exited / crashed.
86+
logger.debug("Intermediate process not found. Querying all process to find MATLAB")
87+
for process in psutil.process_iter():
88+
if (
89+
process.name() == "MATLAB.exe"
90+
and process.ppid() == intermediate_proc.pid
91+
):
92+
matlab = process
93+
break
94+
95+
assert matlab != None, "MATLAB Process ID not found"
7996

8097
# Return the actual MATLAB processes
81-
return children[0]
98+
return matlab

0 commit comments

Comments
 (0)