def stop(self): pid = pidlockfile.read_pid_from_pidfile(settings.PIDFILE) if pid is None: sys.stderr.write('Failed to read PID from pidfile "%(pidfile)s".\n' % { 'pidfile': settings.PIDFILE, }) sys.exit(1) elif not self._is_pid_running(pid): sys.stderr.write('PID %(pid)s in pidfile "%(pidfile)s" is not running.\n' % { 'pid': pid, 'pidfile': settings.PIDFILE, }) sys.exit(7) else: try: os.kill(pid, signal.SIGTERM) sys.stdout.write('Stopping') while self._is_pid_running(pid): sys.stdout.write('.') sys.stdout.flush() time.sleep(1) sys.stdout.write(' Ok!\n') pidlockfile.remove_existing_pidfile(settings.PIDFILE) sys.exit(0) except OSError as e: sys.stderr.write('Failed to terminate PID %(pid)s: %(message)s.\n' % { 'pid': pid, 'message': e, }) sys.exit(1)
def test_removes_specified_filename(self): """ Should attempt to remove specified PID file filename. """ pidfile_path = self.scenario['path'] expect_mock_output = """\ Called os.remove(%(pidfile_path)r) """ % vars() pidlockfile.remove_existing_pidfile(pidfile_path) scaffold.mock_restore() self.failUnlessMockCheckerMatch(expect_mock_output)
def test_ignores_file_not_exist_error(self): """ Should ignore error if file does not exist. """ pidfile_path = self.scenario['path'] mock_error = OSError(errno.ENOENT, "Not there", pidfile_path) os.remove.mock_raises = mock_error expect_mock_output = """\ Called os.remove(%(pidfile_path)r) """ % vars() pidlockfile.remove_existing_pidfile(pidfile_path) scaffold.mock_restore() self.failUnlessMockCheckerMatch(expect_mock_output)
def stop_worker(args): """Sends SIGTERM to Celery worker""" # Read PID from file pid_file_path, _, _, _ = setup_locations(process=WORKER_PROCESS_NAME) pid = read_pid_from_pidfile(pid_file_path) # Send SIGTERM if pid: worker_process = psutil.Process(pid) worker_process.terminate() # Remove pid file remove_existing_pidfile(pid_file_path)
def start(self, detach=True, debug=False): # Check if the service is already running. pid = pidlockfile.read_pid_from_pidfile(settings.PIDFILE) if pid is not None and self._is_pid_running(pid): sys.stderr.write('PID %(pid)s in pidfile "%(pidfile)s" is already running.\n' % { 'pid': pid, 'pidfile': settings.PIDFILE, }) sys.exit(1) # Remove pidfile (may not exists). pidlockfile.remove_existing_pidfile(settings.PIDFILE) # Adjust daemon context. if not detach: self.detach_process = False self.stdout = sys.stdout self.stderr = sys.stderr # Enter daemon context. with self: # Initializations. pid = os.getpid() self._shutdown_event = multiprocessing.Event() self._logging_queue = multiprocessing.Queue(-1) self._init_logger(debug=debug, console=not detach) # Log. logging.getLogger('varnishsentry').info( 'Starting varnishsentry service (PID %d)', pid) # Launch consumers. for id, config in settings.WORKERS.iteritems(): worker = Consumer( pid, self._shutdown_event, self._logging_queue, id, config, debug) self._workers.append(worker) worker.start() # Periodically check for termination and for terminated workers. while not self._sigterm: try: # Wait for incoming messages (up to 1 second). record = self._logging_queue.get(True, 1) # Process incoming message. if record is not None: logging.getLogger(record.name).handle(record) except: pass # Some worker has terminated? => rebuild the list of workers. if self._sigchld > 0: workers = [] for worker in self._workers: if worker.is_alive(): workers.append(worker) else: worker.terminate() logging.getLogger('varnishsentry').error( 'Worker %s terminated unexpectedly with status ' 'code %d', worker.name, worker.exitcode) workers.append(worker.restart()) self._workers = workers self._sigchld -= 1 # Set shutdown event and wait a few seconds for a graceful shutdown # of all workers. self._shutdown_event.set() retries = 5 while retries > 0: if any([worker.is_alive() for worker in self._workers]): retries = retries - 1 time.sleep(1) else: break # After timeout, force shutdown of any alive worker. for worker in self._workers: if worker.is_alive(): worker.terminate() # Wait for all workers termination. for worker in self._workers: worker.join() # Clean up and exit. pidlockfile.remove_existing_pidfile(settings.PIDFILE) logging.getLogger('varnishsentry').info( 'Shutting down varnishsentry service (PID %d)', pid) sys.exit(0)