1
1
# Copyright 2020-2021 The MathWorks, Inc.
2
2
3
3
import asyncio
4
- from matlab_proxy import mwi_embedded_connector as mwi_connector
5
4
from matlab_proxy import mwi_environment_variables as mwi_env
6
5
from matlab_proxy import util
7
6
import os
@@ -40,8 +39,19 @@ def __init__(self, settings):
40
39
"""
41
40
self .settings = settings
42
41
self .processes = {"matlab" : None , "xvfb" : None }
42
+
43
+ # The port on which MATLAB(launched by this matlab-proxy process) starts on.
43
44
self .matlab_port = None
45
+
46
+ # The file created and written by MATLAB's Embedded connector to signal readiness.
44
47
self .matlab_ready_file = None
48
+
49
+ # The directory in which the instance of MATLAB (launched by this matlab-proxy process) will write logs to.
50
+ self .matlab_ready_file_dir = None
51
+
52
+ # The file created by this instance of matlab-proxy to signal to other matlab-proxy processes
53
+ # that this self.matlab_port will be used by this instance.
54
+ self .mwi_proxy_lock_file = None
45
55
self .licensing = None
46
56
self .tasks = {}
47
57
self .logs = {
@@ -354,8 +364,15 @@ def persist_licensing(self):
354
364
with open (cached_licensing_file , "w" ) as f :
355
365
f .write (json .dumps (self .licensing ))
356
366
357
- def get_free_matlab_port (self ):
358
- """Returns a free port for MATLAB Embedded Connector in the allowed range."""
367
+ def prepare_lock_files_for_MATLAB_launch (self ):
368
+ """Finds and reserves a free port for MATLAB Embedded Connector in the allowed range.
369
+ Creates the lock file to prevent any other matlab-proxy process to use the reserved port of this
370
+ process.
371
+
372
+ Raises:
373
+ e: socket.error if the exception raised is other than port already occupied.
374
+ """
375
+
359
376
# NOTE It is not guranteed that the port will remain free!
360
377
# FIXME Because of https://github.com/http-party/node-http-proxy/issues/1342 the
361
378
# node application in development mode always uses port 31515 to bypass the
@@ -372,16 +389,53 @@ def get_free_matlab_port(self):
372
389
# try-except.
373
390
# s.bind(("", 0))
374
391
# self.matlab_port = s.getsockname()[1]
392
+
375
393
for port in mw .range_matlab_connector_ports ():
376
394
try :
377
395
s = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
378
396
s .bind (("" , port ))
379
- s .close ()
380
- break
397
+
398
+ matlab_ready_file_dir = self .settings ["mwi_logs_root_dir" ] / str (
399
+ port
400
+ )
401
+
402
+ mwi_proxy_lock_file = (
403
+ matlab_ready_file_dir
404
+ / self .settings ["mwi_proxy_lock_file_name" ]
405
+ )
406
+
407
+ matlab_ready_file = matlab_ready_file_dir / "connector.securePort"
408
+
409
+ # Check if the mwi_proxy_lock_file exists.
410
+ # Implies there was a competing matlab-proxy process which found the same port before this process
411
+ if mwi_proxy_lock_file .exists ():
412
+ logger .debug (
413
+ f"Skipping port number { port } for MATLAB as lock file already exists at { mwi_proxy_lock_file } "
414
+ )
415
+ s .close ()
416
+
417
+ else :
418
+ # Create a folder to hold the matlab_ready_file that will be created by MATLAB to signal readiness.
419
+ # This is the same folder to which MATLAB will write logs to.
420
+ matlab_ready_file_dir .mkdir (parents = True , exist_ok = True )
421
+
422
+ # Creating the mwi_proxy.lock file to indicate to any other matlab-proxy processes
423
+ # that this self.matlab_port number is taken up by this process.
424
+ mwi_proxy_lock_file .touch ()
425
+
426
+ # Update member variables of AppState class
427
+
428
+ # Store the port number on which MATLAB will be launched for this matlab-proxy process.
429
+ self .matlab_port = port
430
+ self .mwi_proxy_lock_file = mwi_proxy_lock_file
431
+ self .matlab_ready_file_dir = matlab_ready_file_dir
432
+ self .matlab_ready_file = matlab_ready_file
433
+ s .close ()
434
+ return
435
+
381
436
except socket .error as e :
382
437
if e .errno != errno .EADDRINUSE :
383
438
raise e
384
- return port
385
439
386
440
async def start_matlab (self , restart_matlab = False ):
387
441
"""Start MATLAB.
@@ -423,15 +477,14 @@ async def start_matlab(self, restart_matlab=False):
423
477
self .error = None
424
478
self .logs ["matlab" ].clear ()
425
479
426
- # Reserve a port for MATLAB Embedded Connector
427
- self .matlab_port = self . get_free_matlab_port ()
480
+ # Finds and reserves a free port, then prepare lock files for the MATLAB process.
481
+ self .prepare_lock_files_for_MATLAB_launch ()
428
482
429
- # Create a folder to hold the matlab_ready_file that will be created by MATLAB to signal readiness
430
- self .matlab_ready_file , matlab_log_dir = mwi_connector .get_matlab_ready_file (
431
- self .matlab_port
432
- )
433
- logger .debug (f"MATLAB_LOG_DIR:{ str (matlab_log_dir )} " )
483
+ logger .debug (f"MATLAB_LOG_DIR:{ str ( self .matlab_ready_file_dir )} " )
434
484
logger .debug (f"MATLAB_READY_FILE:{ str (self .matlab_ready_file )} " )
485
+ logger .debug (
486
+ f"Created MWI proxy lock file for this matlab-proxy process at { self .mwi_proxy_lock_file } "
487
+ )
435
488
436
489
# Configure the environment MATLAB needs to start
437
490
matlab_env = os .environ .copy ()
@@ -445,7 +498,8 @@ async def start_matlab(self, restart_matlab=False):
445
498
)
446
499
matlab_env ["MWAPIKEY" ] = self .settings ["mwapikey" ]
447
500
# The matlab ready file is written into this location by MATLAB
448
- matlab_env ["MATLAB_LOG_DIR" ] = str (matlab_log_dir )
501
+ # The matlab_ready_file_dir is where MATLAB will write any subsequent logs
502
+ matlab_env ["MATLAB_LOG_DIR" ] = str (self .matlab_ready_file_dir )
449
503
matlab_env ["MW_CD_ANYWHERE_ENABLED" ] = "true"
450
504
if self .licensing ["type" ] == "mhlm" :
451
505
matlab_env ["MLM_WEB_LICENSE" ] = "true"
@@ -538,15 +592,16 @@ async def stop_matlab(self):
538
592
xvfb .terminate ()
539
593
waiters .append (xvfb .wait ())
540
594
541
- # Clean up matlab_ready_file
542
595
try :
596
+ # Clean up both connector.securePort file and mwi_proxy_lock_file
543
597
if self .matlab_ready_file is not None :
544
- logger .info (
545
- f"Cleaning up matlab_ready_file...{ str (self .matlab_ready_file )} "
546
- )
547
598
self .matlab_ready_file .unlink ()
599
+
600
+ if self .mwi_proxy_lock_file is not None :
601
+ self .mwi_proxy_lock_file .unlink ()
602
+
548
603
except FileNotFoundError :
549
- # Some other process deleted this file
604
+ # Files won't exist when stop_matlab is called for the first time.
550
605
pass
551
606
552
607
# Wait for termination
0 commit comments