Skip to content

Commit a0abbd8

Browse files
committed
Fixes hang when stopping MATLAB from matlab-proxy via interrupt signal.
This issue usually only occurs when MATLAB starts MathWorksServiceHost process for the first time through matlab-proxy. In this state, the matlab-proxy process shares a pipe with the MathWorksServiceHost process and waits for ever for that pipe to close. This change closes the shared stderr pipe before waiting for MATLAB to terminate.
1 parent 5a52fce commit a0abbd8

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

matlab_proxy/app_state.py

+31-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2020-2024 The MathWorks, Inc.
1+
# Copyright 2020-2025 The MathWorks, Inc.
22

33
import asyncio
44
import contextlib
@@ -436,8 +436,10 @@ async def __update_matlab_state_based_on_endpoint_to_use(
436436

437437
else:
438438
await self.matlab_state_updater_lock.release()
439-
await self._update_matlab_state_based_on_ready_file_and_connector_status(
440-
matlab_endpoint_to_use
439+
await (
440+
self._update_matlab_state_based_on_ready_file_and_connector_status(
441+
matlab_endpoint_to_use
442+
)
441443
)
442444
logger.debug(
443445
f"{this_task}: Required processes are ready, Embedded Connector status is '{self.get_matlab_state()}'"
@@ -1243,7 +1245,7 @@ async def __update_matlab_port(self, delay: int):
12431245
delay (int): time delay in seconds before retrying the file read operation
12441246
"""
12451247
logger.debug(
1246-
f'updating matlab_port information from {self.matlab_session_files["matlab_ready_file"]}'
1248+
f"updating matlab_port information from {self.matlab_session_files['matlab_ready_file']}"
12471249
)
12481250
try:
12491251
await asyncio.wait_for(
@@ -1415,6 +1417,10 @@ async def stop_matlab(self, force_quit=False):
14151417
waiters = []
14161418
if matlab is not None:
14171419
if system.is_posix() and matlab.returncode is None:
1420+
# Close the stderr stream to prevent indefinite hanging on it due to a child
1421+
# process inheriting it, fixes https://github.com/mathworks/matlab-proxy/issues/44
1422+
self._close_matlab_stderr_stream(matlab)
1423+
14181424
# Sending an exit request to the embedded connector takes time.
14191425
# When MATLAB is in a "starting" state (implies the Embedded connector is not up)
14201426
# OR
@@ -1427,23 +1433,9 @@ async def stop_matlab(self, force_quit=False):
14271433
else:
14281434
logger.debug("Sending HTTP request to stop the MATLAB process...")
14291435
try:
1430-
import sys
1431-
14321436
# Send HTTP request
14331437
await self.__send_stop_request_to_matlab()
14341438

1435-
# Close the stderr stream to prevent indefinite hanging on it due to a child
1436-
# process inheriting it, fixes https://github.com/mathworks/matlab-proxy/issues/44
1437-
stderr_stream = matlab._transport.get_pipe_transport(
1438-
sys.stderr.fileno()
1439-
)
1440-
if stderr_stream:
1441-
logger.debug(
1442-
"Closing matlab process stderr stream: %s",
1443-
stderr_stream,
1444-
)
1445-
stderr_stream.close()
1446-
14471439
# Wait for matlab to shutdown gracefully
14481440
await matlab.wait()
14491441

@@ -1461,9 +1453,10 @@ async def stop_matlab(self, force_quit=False):
14611453
try:
14621454
matlab.terminate()
14631455
await matlab.wait()
1464-
except:
1465-
pass
1466-
1456+
except Exception as ex:
1457+
logger.debug(
1458+
"Received an exception while terminating matlab: %s", ex
1459+
)
14671460
else:
14681461
# In a windows system
14691462
if system.is_windows() and matlab.is_running():
@@ -1533,6 +1526,23 @@ async def stop_matlab(self, force_quit=False):
15331526
self.matlab_port = None
15341527
logger.debug("Completed Shutdown!!!")
15351528

1529+
def _close_matlab_stderr_stream(self, matlab):
1530+
"""
1531+
This method attempts to close the stderr stream associated with the MATLAB process
1532+
to prevent potential resource leaks. It logs a debug message if the stream is
1533+
successfully closed.
1534+
1535+
Args:
1536+
matlab: The MATLAB process reference.
1537+
"""
1538+
stderr_stream = matlab._transport.get_pipe_transport(sys.stderr.fileno())
1539+
if stderr_stream:
1540+
logger.debug(
1541+
"Closing matlab process stderr stream: %s",
1542+
stderr_stream,
1543+
)
1544+
stderr_stream.close()
1545+
15361546
async def handle_matlab_output(self):
15371547
"""Parse MATLAB output from stdout and raise errors if any."""
15381548
matlab = self.processes["matlab"]

0 commit comments

Comments
 (0)