def start_service(api_class, service_class, log, services=None, host='localhost', port=9100): """Start a Data API service. Args: api_class (BaseService): The custom API service class, e.g., `doekbase.data_api.taxonomy.taxon.api.TaxonService` service_class (type): The Thrift auto-generated service class log (logging.Logger): Logging object services (dict): Service configuration dictionary, passed to constructor of the `api_class`. host (str): Service host (will default to 'localhost') port (int): Service port, e.g. 9101 """ assert issubclass(api_class, BaseService), \ 'Invalid "api_class": must be a subclass of ' \ 'doekbase.data_api.service_core.BaseService' assert hasattr(service_class, 'Processor'), 'Invalid "service_class": ' \ 'missing "Processor" attribute' assert isinstance(port, int), 'The "port" must be an integer' log.debug('method=start_service state=begin host={host} port={port:d}' .format(host=host, port=port)) # Create server services = services or SERVICES_DICT handler = api_class(services) processor = service_class.Processor(handler) pfactory = TBinaryProtocol.TBinaryProtocolFactory() resource = TTwisted.ThriftResource(processor, pfactory, pfactory) site = twisted.web.server.Site(resource=resource) twisted.internet.reactor.listenTCP(port, site, interface=host) # Run server sname = api_class.__name__ shost = host or 'localhost' log.info('msg="Starting {} server at {}:{}"'.format(sname, shost, port)) log.debug('method=twisted.internet.reactor.run state=begin') try: twisted.internet.reactor.run() except Exception as err: log.error('msg="Abort {} server on error"'.format(sname)) log.error('method=twisted.internet.reactor.run state=error ' 'error_message={e}'.format(e=err)) raise finally: log.debug('method=twisted.internet.reactor.run state=end') return 0
def start_service(api_class, service_class, log, services=None, host='localhost', port=9100, killprocgrp=False): """Start a Data API service. Args: api_class (BaseService): The custom API service class, e.g., `doekbase.data_api.taxonomy.taxon.api.TaxonService` service_class (type): The Thrift auto-generated service class log (logging.Logger): Logging object services (dict): Service configuration dictionary, passed to constructor of the `api_class`. host (str): Service host (will default to 'localhost') port (int): Service port, e.g. 9101 killprocgrp (bool): if True, kill process group on exit """ assert issubclass(api_class, BaseService), \ 'Invalid "api_class": must be a subclass of ' \ 'doekbase.data_api.service_core.BaseService' assert hasattr(service_class, 'Processor'), 'Invalid "service_class": ' \ 'missing "Processor" attribute' assert isinstance(port, int), 'The "port" must be an integer' svc_t0 = util.log_start(log, 'start_service', kvp=dict(host=host, port=port)) # Create server services = services or SERVICES_DICT handler = api_class(services) processor = service_class.Processor(handler) pfactory = TBinaryProtocol.TBinaryProtocolFactory() resource = TTwisted.ThriftResource(processor, pfactory, pfactory) site = twisted.web.server.Site(resource=resource) twisted.internet.reactor.listenTCP(port, site, interface=host) # Kill entire process group on shutdown if killprocgrp: twisted.internet.reactor.addSystemEventTrigger( 'before', 'shutdown', functools.partial(kill_process_group, log=log)) # Run server sname = api_class.__name__ shost = host or 'localhost' util.log_start(log, 'server', kvp=dict(name=sname, host=shost, port=port)) t0 = util.log_start(log, 'twisted.internet.reactor.run', level=logging.DEBUG) try: twisted.internet.reactor.run() except Exception as err: log.error('msg="Abort {} server on error"'.format(sname)) util.log_end(log, t0, 'twisted.internet.reactor.run', status_code=1, level=logging.ERROR, kvp=dict(msg=err)) raise finally: util.log_end(log, t0, 'twisted.internet.reactor.run') util.log_end(log, svc_t0, 'start_service', kvp=dict(host=host, port=port)) return 0