Source code for servermgr.base

# -*- mode: python; tab-width:8; py-indent-offset:4; indent-tabs-mode:nil -*-

"""
Interface definition and base implementation for all subprocess managers.
"""

import socket
import time

#pylint: disable=R0921
#abstract class not implemented;

[docs]class ManagerInterface(object): """ This abstract class defines the interface implemented by all Managers. """
[docs] def health(self): """ Check the health of the worker subprocess. :raises: **WorkerError** if the worker subprocess is not responding. """ raise NotImplementedError
[docs] def start(self, wait=True, timeout=10.0): """ Start the worker subprocess. :param wait: If true, call self.ready_wait() after starting the subprocess. :param timeout: When calling ready_wait(), use this timeout value. :type timeout: float, number of seconds """ raise NotImplementedError
[docs] def ready_wait(self, timeout=10.0): """ Wait for the worker to be ready to handle requests. :param timeout: Give the server this many seconds to start. If the timeout expires before the server has started, kill the server and raise WorkerError. :type timeout: float, seconds :raises: **WorkerError** if the worker is not ready within the time limit. """ raise NotImplementedError
[docs] def stop(self, wait=True): """ Stop the worker subprocess. :param wait: If True, wait for the worker to exit. :type wait: boolean """ raise NotImplementedError
[docs] def wait(self): """Wait for the worker process to exit.""" raise NotImplementedError
[docs]class WorkerError(Exception): """Exception raised when a Worker fails to start or fails to respond. """ def __init__(self, exception, *args, **kwargs): super(WorkerError, self).__init__(*args, **kwargs) self.exception = exception def __str__(self): val = super(WorkerError, self).__str__() if self.exception == None: return val return val + " " + str(self.exception)
[docs]def address_in_use(host, port): """ Check to see if there is a listener on host:port. :param host: the interface to check; :type host: string :param port: the post to check; :type port: int :returns: **True** if there is a listener, else **False**. """ try: s__ = socket.create_connection((host, port)) s__.close() return True except socket.error: return False
[docs]def address_free_check(host, port): """ Raise an exception if host:port is in use. :param host: the interface to check; :type host: string :param port: the post to check; :type port: int :raises: **WorkerError** if the address is in use. """ if address_in_use(host, port): raise WorkerError(None, "address already in use", host, port) #pylint: disable=R0922 #abstract class only referenced one time;
[docs]class ManagerBase(object): """ :param name: Name of manager, displayed in error and log messages. :keyword process_name: the string to be displayed by the 'ps command. This is the base implementation of the Manager class. Implementations are provided for the following methods: * ready_wait() * stop() * wait() The following methods must be implemented by the subclass: * health() * start() """ def __init__(self, name, process_name=None): """Initialize the Manager object.""" self.process = None self.name = name self.process_name = process_name def __del__(self): self.stop()
[docs] def health(self): """Check the worker subprocess health. :raises: **NotImplementedError** must be implemented by subclass. """ raise NotImplementedError
[docs] def start(self, wait=True, timeout=10.0): """ Start the worker subprocess. :raises: **NotImplementedError** must be implemented by subclass. """ raise NotImplementedError
[docs] def ready_wait(self, timeout=10.0, verbose=False): """Wait until the worker subprocess is responding to requests. :param timeout: Give the server this many seconds to start. If the timeout expires before the server has started, kill the server and raise WorkerError. :type timeout: float, seconds :raises: **WorkerError** if the worker is not ready within the time limit. :raises: **WorkerError** if there is no subprocess. """ if not self.process: raise WorkerError(None, self.name + " No subprocess") start_time = time.time() time_delta = 0.5 status = self.process.poll() while status == None: # status == None => process is running; try: self.health() if verbose: print "server %s is ready." % self.name return except WorkerError: pass if time.time() - start_time > timeout: self.process.terminate() self.process.wait() self.process = None raise WorkerError(None, self.name + " Taking too long to start.") time.sleep(time_delta) status = self.process.poll() errors = None if hasattr(self.process, "stderr"): errors = self.process.stderr.read() self.process = None raise WorkerError(self.name, errors)
[docs] def stop(self, wait=True): """ Terminate the worker subprocess. :param wait: If True, wait for the worker to exit. :type wait: boolean """ if self.process: self.process.terminate() if wait: self.process.wait() self.process = None
[docs] def wait(self): """Wait for the worker process to exit.""" if self.process: self.process.wait() self.process = None