1717import numpy as np
1818from tqdm import tqdm
1919from grpc ._channel import _InactiveRpcError , _MultiThreadedRendezvous
20+ from grpc_health .v1 import health_pb2 , health_pb2_grpc
2021from ansys .grpc .mapdl import mapdl_pb2 as pb_types
2122from ansys .grpc .mapdl import mapdl_pb2_grpc as mapdl_grpc
2223from ansys .grpc .mapdl import ansys_kernel_pb2 as anskernel
2324
2425from ansys .mapdl .core .mapdl import _MapdlCore
25- from ansys .mapdl .core .errors import MapdlExitedError , protect_grpc
26+ from ansys .mapdl .core .errors import MapdlExitedError , protect_grpc , MapdlRuntimeError
2627from ansys .mapdl .core .misc import supress_logging , run_as_prep7 , last_created
2728from ansys .mapdl .core .post import PostProcessing
2829from ansys .mapdl .core .common_grpc import (parse_chunks ,
@@ -194,6 +195,8 @@ def __init__(self, ip='127.0.0.1', port=None, timeout=15, loglevel='WARNING',
194195 self ._channel_str = None
195196 self ._local = ip in ['127.0.0.1' , '127.0.1.1' , 'localhost' ]
196197 self ._ip = ip
198+ self ._health_response_queue = None
199+ self ._exiting = False
197200
198201 if port is None :
199202 from ansys .mapdl .core .launcher import MAPDL_DEFAULT_PORT
@@ -298,6 +301,12 @@ def _connect(self, port, timeout=5, set_no_abort=True):
298301 self ._post = PostProcessing (self )
299302 self ._xpl = ansXpl (self )
300303
304+ # TODO: version check
305+
306+
307+ # enable health check
308+ self ._enable_health_check ()
309+
301310 # housekeeping otherwise, many failures in a row will cause
302311 # MAPDL to exit without returning anything useful. Also
303312 # avoids abort in batch mode if set.
@@ -306,6 +315,48 @@ def _connect(self, port, timeout=5, set_no_abort=True):
306315
307316 return True
308317
318+ def _enable_health_check (self ):
319+ """Places the status of the health check in _health_response_queue"""
320+ def _consume_responses (response_iterator , response_queue ):
321+ try :
322+ for response in response_iterator :
323+ response_queue .put (response )
324+ # NOTE: we're doing absolutely nothing with this as
325+ # this point since the server side health check
326+ # doesn't change state.
327+ except Exception as err :
328+ if self ._exiting :
329+ return
330+ self ._exited = True
331+ raise MapdlExitedError ('Lost connection with MAPDL server' ) from None
332+
333+ # enable health check
334+ from queue import Queue
335+ request = health_pb2 .HealthCheckRequest ()
336+ self ._health_stub = health_pb2_grpc .HealthStub (self ._channel )
337+ rendezvous = self ._health_stub .Watch (request )
338+
339+ # health check feature implemented after 2020R2
340+ try :
341+ status = rendezvous .next ()
342+ except Exception as err :
343+ if err .code ().name != 'UNIMPLEMENTED' :
344+ raise err
345+ return
346+
347+ if status .status != health_pb2 .HealthCheckResponse .SERVING :
348+ raise MapdlRuntimeError ('Unable to enable health check and/or connect to'
349+ ' the MAPDL server' )
350+
351+ self ._health_response_queue = Queue ()
352+
353+ # allow main process to exit by setting daemon to true
354+ thread = threading .Thread (target = _consume_responses ,
355+ args = (rendezvous , self ._health_response_queue ),
356+ daemon = True )
357+ thread .start ()
358+
359+
309360 def _launch (self , start_parm ):
310361 """Launch a local session of MAPDL in gRPC mode.
311362
@@ -441,6 +492,7 @@ def exit(self, save=False):
441492 --------
442493 >>> mapdl.exit()
443494 """
495+ self ._exiting = True
444496 self ._log .debug ('Exiting MAPDL' )
445497
446498 if save :
0 commit comments