Skip to content

Commit 66c8580

Browse files
committed
Bug fix:Fix RuntimeError on SIGINT signal (CTRL+C)
A dictionary to hold MWI's async tasks Use simple await for matlab_starter and init_licensing
1 parent 1ca4960 commit 66c8580

File tree

3 files changed

+50
-19
lines changed

3 files changed

+50
-19
lines changed

jupyter_matlab_proxy/app.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -340,19 +340,23 @@ async def matlab_starter(app):
340340

341341

342342
async def start_background_tasks(app):
343-
loop = asyncio.get_running_loop()
344-
app["license_init"] = loop.create_task(license_init(app))
345-
app["matlab_starter"] = loop.create_task(matlab_starter(app))
343+
await license_init(app)
344+
await matlab_starter(app)
346345

347346

348347
async def cleanup_background_tasks(app):
349-
348+
logger = mwi_logger.get()
350349
state = app["state"]
350+
tasks = state.tasks
351+
for task_name, task in tasks.items():
352+
if not task.cancelled():
353+
logger.debug(f"Cancelling MWI task: {task_name} : {task} ")
354+
task.cancel()
355+
try:
356+
await task
357+
except asyncio.CancelledError:
358+
pass
351359

352-
app["license_init"].cancel()
353-
app["matlab_starter"].cancel()
354-
await app["license_init"]
355-
await app["matlab_starter"]
356360
await state.stop_matlab()
357361

358362

@@ -427,9 +431,21 @@ def main():
427431

428432
async def shutdown():
429433
logger.info("Shutting down MATLAB proxy-app")
434+
for task in asyncio.Task.all_tasks():
435+
logger.debug(f"calling cancel on all_tasks: {task}")
436+
task.cancel()
430437
await app.shutdown()
431438
await app.cleanup()
432-
# waiting here to allow matlab to finish exiting.
433-
await asyncio.sleep(5)
434439

435-
loop.run_until_complete(shutdown())
440+
asyncio.ensure_future(exit())
441+
442+
try:
443+
loop.run_until_complete(shutdown())
444+
except:
445+
pass
446+
447+
logger.info(
448+
"Finished shutting down. Thank you for using the MATLAB web desktop proxy."
449+
)
450+
loop.close()
451+
sys.exit(0)

jupyter_matlab_proxy/app_state.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(self, settings):
3434
self.processes = {"matlab": None, "xvfb": None}
3535
self.matlab_port = None
3636
self.licensing = None
37+
self.tasks = {}
3738
self.logs = {
3839
"matlab": deque(maxlen=200),
3940
}
@@ -66,6 +67,14 @@ def __reset_and_delete_cached_licensing(self):
6667
self.licensing = None
6768
self.__delete_cached_licensing_file()
6869

70+
async def __update_and_persist_licensing(self):
71+
successful_update = await self.update_entitlements()
72+
if successful_update:
73+
self.persist_licensing()
74+
else:
75+
self.__reset_and_delete_cached_licensing()
76+
return successful_update
77+
6978
async def init_licensing(self):
7079
"""Initialize licensing from environment variable or cached file.
7180
@@ -122,12 +131,9 @@ async def init_licensing(self):
122131
) - timedelta(hours=1)
123132

124133
if expiry_window > datetime.now(timezone.utc):
125-
successful_update = await self.update_entitlements()
134+
successful_update = self.__update_and_persist_licensing()
126135
if successful_update:
127136
logger.info("Successful re-use of cached information.")
128-
self.persist_licensing()
129-
else:
130-
self.__reset_and_delete_cached_licensing()
131137
else:
132138
self.__reset_and_delete_cached_licensing()
133139
else:
@@ -198,8 +204,9 @@ async def set_licensing_mhlm(
198204
"entitlement_id": entitlement_id,
199205
}
200206

201-
await self.update_entitlements()
202-
self.persist_licensing()
207+
successful_update = self.__update_and_persist_licensing()
208+
if successful_update:
209+
logger.info("Login successful, persisting login information.")
203210

204211
except OnlineLicensingError as e:
205212
self.error = e
@@ -445,16 +452,19 @@ async def start_matlab(self, restart=False):
445452
self.processes["matlab"] = matlab
446453
logger.debug(f"Started MATLAB (PID={matlab.pid})")
447454

448-
async def reader():
455+
async def matlab_stderr_reader():
456+
logger.info("Starting task to save error logs from MATLAB")
449457
while not self.processes["matlab"].stderr.at_eof():
458+
logger.info("Checking for any error logs from MATLAB to save...")
450459
line = await self.processes["matlab"].stderr.readline()
451460
if line is None:
452461
break
462+
logger.info("Saving error logs from MATLAB.")
453463
self.logs["matlab"].append(line)
454464
await self.handle_matlab_output()
455465

456466
loop = asyncio.get_running_loop()
457-
loop.create_task(reader())
467+
self.tasks["matlab_stderr_reader"] = loop.create_task(matlab_stderr_reader())
458468

459469
async def stop_matlab(self):
460470
"""Terminate MATLAB."""
@@ -497,12 +507,15 @@ async def handle_matlab_output(self):
497507
matlab = self.processes["matlab"]
498508

499509
# Wait for MATLAB process to exit
510+
logger.info("handle_matlab_output Waiting for MATLAB to exit...")
500511
await matlab.wait()
501512

502513
rc = self.processes["matlab"].returncode
514+
logger.info(f"handle_matlab_output MATLAB has exited with errorcode: {rc}")
503515

504516
# Look for errors if MATLAB was not intentionally stopped and had an error code
505517
if len(self.logs["matlab"]) > 0 and self.processes["matlab"].returncode != 0:
518+
logger.info(f"handle_matlab_output Some error was found!")
506519
err = None
507520
logs = [log.decode().rstrip() for log in self.logs["matlab"]]
508521

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def run(self):
5454
version="0.2.0",
5555
url="https://github.com/mathworks/jupyter-matlab-proxy",
5656
author="The MathWorks, Inc.",
57+
author_email="[email protected]",
58+
license="MATHWORKS CLOUD REFERENCE ARCHITECTURE LICENSE",
5759
description="Jupyter extension to proxy MATLAB JavaScript Desktop",
5860
packages=setuptools.find_packages(exclude=["devel", "tests"]),
5961
keywords=["Jupyter"],

0 commit comments

Comments
 (0)