##// END OF EJS Templates
add check_pid, and handle stale PID info in ipcluster....
MinRK -
Show More
@@ -23,6 +23,8 b' import re'
23 import shutil
23 import shutil
24 import sys
24 import sys
25
25
26 from subprocess import Popen, PIPE
27
26 from IPython.config.loader import PyFileConfigLoader
28 from IPython.config.loader import PyFileConfigLoader
27 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
28 from IPython.core.application import Application, BaseAppConfigLoader
30 from IPython.core.application import Application, BaseAppConfigLoader
@@ -534,4 +536,31 b' class ApplicationWithClusterDir(Application):'
534 return pid
536 return pid
535 else:
537 else:
536 raise PIDFileError('pid file not found: %s' % pid_file)
538 raise PIDFileError('pid file not found: %s' % pid_file)
537
539
540 def check_pid(self, pid):
541 if os.name == 'nt':
542 try:
543 import ctypes
544 # returns 0 if no such process (of ours) exists
545 # positive int otherwise
546 p = ctypes.windll.kernel32.OpenProcess(1,0,pid)
547 except Exception:
548 self.log.warn(
549 "Could not determine whether pid %i is running via `OpenProcess`. "
550 " Making the likely assumption that it is."%pid
551 )
552 return True
553 return bool(p)
554 else:
555 try:
556 p = Popen(['ps','x'], stdout=PIPE, stderr=PIPE)
557 output,_ = p.communicate()
558 except OSError:
559 self.log.warn(
560 "Could not determine whether pid %i is running via `ps x`. "
561 " Making the likely assumption that it is."%pid
562 )
563 return True
564 pids = map(int, re.findall(r'^\W*\d+', output, re.MULTILINE))
565 return pid in pids
566 No newline at end of file
@@ -21,6 +21,7 b' import os'
21 import re
21 import re
22 import signal
22 import signal
23
23
24 from subprocess import check_call, CalledProcessError, PIPE
24 import zmq
25 import zmq
25 from zmq.eventloop import ioloop
26 from zmq.eventloop import ioloop
26
27
@@ -497,13 +498,17 b' class IPClusterApp(ApplicationWithClusterDir):'
497 except PIDFileError:
498 except PIDFileError:
498 pass
499 pass
499 else:
500 else:
500 self.log.critical(
501 if self.check_pid(pid):
501 'Cluster is already running with [pid=%s]. '
502 self.log.critical(
502 'use "ipcluster stop" to stop the cluster.' % pid
503 'Cluster is already running with [pid=%s]. '
503 )
504 'use "ipcluster stop" to stop the cluster.' % pid
504 # Here I exit with a unusual exit status that other processes
505 )
505 # can watch for to learn how I existed.
506 # Here I exit with a unusual exit status that other processes
506 self.exit(ALREADY_STARTED)
507 # can watch for to learn how I existed.
508 self.exit(ALREADY_STARTED)
509 else:
510 self.remove_pid_file()
511
507
512
508 # Now log and daemonize
513 # Now log and daemonize
509 self.log.info(
514 self.log.info(
@@ -526,7 +531,8 b' class IPClusterApp(ApplicationWithClusterDir):'
526 pass
531 pass
527 else:
532 else:
528 raise
533 raise
529 self.remove_pid_file()
534 finally:
535 self.remove_pid_file()
530
536
531 def start_app_engines(self):
537 def start_app_engines(self):
532 """Start the app for the start subcommand."""
538 """Start the app for the start subcommand."""
@@ -563,23 +569,41 b' class IPClusterApp(ApplicationWithClusterDir):'
563 pid = self.get_pid_from_file()
569 pid = self.get_pid_from_file()
564 except PIDFileError:
570 except PIDFileError:
565 self.log.critical(
571 self.log.critical(
566 'Problem reading pid file, cluster is probably not running.'
572 'Could not read pid file, cluster is probably not running.'
567 )
573 )
568 # Here I exit with a unusual exit status that other processes
574 # Here I exit with a unusual exit status that other processes
569 # can watch for to learn how I existed.
575 # can watch for to learn how I existed.
576 self.remove_pid_file()
570 self.exit(ALREADY_STOPPED)
577 self.exit(ALREADY_STOPPED)
571 else:
578
572 if os.name=='posix':
579 if not self.check_pid(pid):
573 sig = config.Global.signal
580 self.log.critical(
574 self.log.info(
581 'Cluster [pid=%r] is not running.' % pid
575 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
582 )
576 )
583 self.remove_pid_file()
584 # Here I exit with a unusual exit status that other processes
585 # can watch for to learn how I existed.
586 self.exit(ALREADY_STOPPED)
587
588 elif os.name=='posix':
589 sig = config.Global.signal
590 self.log.info(
591 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
592 )
593 try:
577 os.kill(pid, sig)
594 os.kill(pid, sig)
578 elif os.name=='nt':
595 except OSError:
579 # As of right now, we don't support daemonize on Windows, so
596 self.log.error("Stopping cluster failed, assuming already dead.",
580 # stop will not do anything. Minimally, it should clean up the
597 exc_info=True)
581 # old .pid files.
582 self.remove_pid_file()
598 self.remove_pid_file()
599 elif os.name=='nt':
600 try:
601 # kill the whole tree
602 p = check_call(['taskkill', '-pid', str(pid), '-t', '-f'], stdout=PIPE,stderr=PIPE)
603 except (CalledProcessError, OSError):
604 self.log.error("Stopping cluster failed, assuming already dead.",
605 exc_info=True)
606 self.remove_pid_file()
583
607
584
608
585 def launch_new_instance():
609 def launch_new_instance():
General Comments 0
You need to be logged in to leave comments. Login now