@@ -338,41 +338,84 @@ def version(self):
338338return self ._pg_version
339339
340340def _try_shutdown (self ,max_attempts ,with_force = False ):
341+ assert type (max_attempts )== int # noqa: E721
342+ assert type (with_force )== bool # noqa: E721
343+ assert max_attempts > 0
344+
341345attempts = 0
346+
347+ # try stopping server N times
348+ while attempts < max_attempts :
349+ attempts += 1
350+ try :
351+ self .stop ()
352+ except ExecUtilException :
353+ continue # one more time
354+ except Exception :
355+ eprint ('cannot stop node {}' .format (self .name ))
356+ break
357+
358+ return # OK
359+
360+ # If force stopping is enabled and PID is valid
361+ if not with_force :
362+ return False
363+
342364node_pid = self .pid
365+ assert node_pid is not None
366+ assert type (node_pid )== int # noqa: E721
343367
344- if node_pid > 0 :
345- # try stopping server N times
346- while attempts < max_attempts :
347- try :
348- self .stop ()
349- break # OK
350- except ExecUtilException :
351- pass # one more time
352- except Exception :
353- eprint ('cannot stop node {}' .format (self .name ))
354- break
355-
356- attempts += 1
357-
358- # If force stopping is enabled and PID is valid
359- if with_force and node_pid != 0 :
360- # If we couldn't stop the node
361- p_status_output = self .os_ops .exec_command (cmd = f'ps -o pid= -p{ node_pid } ' ,shell = True ,ignore_errors = True ).decode ('utf-8' )
362- if self .status ()!= NodeStatus .Stopped and p_status_output and str (node_pid )in p_status_output :
363- try :
364- eprint (f'Force stopping node{ self .name } with PID{ node_pid } ' )
365- self .os_ops .kill (node_pid ,signal .SIGKILL ,expect_error = False )
366- except Exception :
367- # The node has already stopped
368- pass
369-
370- # Check that node stopped - print only column pid without headers
371- p_status_output = self .os_ops .exec_command (f'ps -o pid= -p{ node_pid } ' ,shell = True ,ignore_errors = True ).decode ('utf-8' )
372- if p_status_output and str (node_pid )in p_status_output :
373- eprint (f'Failed to stop node{ self .name } .' )
374- else :
375- eprint (f'Node{ self .name } has been stopped successfully.' )
368+ if node_pid == 0 :
369+ return
370+
371+ # TODO: [2025-02-28] It is really the old ugly code. We have to rewrite it!
372+
373+ ps_command = ['ps' ,'-o' ,'pid=' ,'-p' ,str (node_pid )]
374+
375+ ps_output = self .os_ops .exec_command (cmd = ps_command ,shell = True ,ignore_errors = True ).decode ('utf-8' )
376+ assert type (ps_output )== str # noqa: E721
377+
378+ if ps_output == "" :
379+ return
380+
381+ if ps_output != str (node_pid ):
382+ __class__ ._throw_bugcheck__unexpected_result_of_ps (
383+ ps_output ,
384+ ps_command )
385+
386+ try :
387+ eprint ('Force stopping node {0} with PID {1}' .format (self .name ,node_pid ))
388+ self .os_ops .kill (node_pid ,signal .SIGKILL ,expect_error = False )
389+ except Exception :
390+ # The node has already stopped
391+ pass
392+
393+ # Check that node stopped - print only column pid without headers
394+ ps_output = self .os_ops .exec_command (cmd = ps_command ,shell = True ,ignore_errors = True ).decode ('utf-8' )
395+ assert type (ps_output )== str # noqa: E721
396+
397+ if ps_output == "" :
398+ eprint ('Node {0} has been stopped successfully.' .format (self .name ))
399+ return
400+
401+ if ps_output == str (node_pid ):
402+ eprint ('Failed to stop node {0}.' .format (self .name ))
403+ return
404+
405+ __class__ ._throw_bugcheck__unexpected_result_of_ps (
406+ ps_output ,
407+ ps_command )
408+
409+ @staticmethod
410+ def _throw_bugcheck__unexpected_result_of_ps (result ,cmd ):
411+ assert type (result )== str # noqa: E721
412+ assert type (cmd )== list # noqa: E721
413+ errLines = []
414+ errLines .append ("[BUG CHECK] Unexpected result of command ps:" )
415+ errLines .append (result )
416+ errLines .append ("-----" )
417+ errLines .append ("Command line is {0}" .format (cmd ))
418+ raise RuntimeError ("\n " .join (errLines ))
376419
377420def _assign_master (self ,master ):
378421"""NOTE: this is a private method!"""