| # Copyright 2020 The gRPC authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """The Python implementation of the GRPC helloworld.Greeter server.""" |
| |
| import argparse |
| from concurrent import futures |
| import logging |
| import socket |
| |
| import grpc |
| from grpc_health.v1 import health |
| from grpc_health.v1 import health_pb2 |
| from grpc_health.v1 import health_pb2_grpc |
| from grpc_reflection.v1alpha import reflection |
| import helloworld_pb2 |
| import helloworld_pb2_grpc |
| |
| _DESCRIPTION = "A general purpose phony server." |
| |
| _LISTEN_HOST = "0.0.0.0" |
| |
| _THREAD_POOL_SIZE = 256 |
| |
| logger = logging.getLogger() |
| console_handler = logging.StreamHandler() |
| formatter = logging.Formatter(fmt='%(asctime)s: %(levelname)-8s %(message)s') |
| console_handler.setFormatter(formatter) |
| logger.addHandler(console_handler) |
| |
| |
| class Greeter(helloworld_pb2_grpc.GreeterServicer): |
| |
| def __init__(self, hostname: str): |
| self._hostname = hostname if hostname else socket.gethostname() |
| |
| def SayHello(self, request: helloworld_pb2.HelloRequest, |
| context: grpc.ServicerContext) -> helloworld_pb2.HelloReply: |
| return helloworld_pb2.HelloReply( |
| message=f"Hello {request.name} from {self._hostname}!") |
| |
| |
| def _configure_maintenance_server(server: grpc.Server, |
| maintenance_port: int) -> None: |
| listen_address = f"{_LISTEN_HOST}:{maintenance_port}" |
| server.add_insecure_port(listen_address) |
| |
| # Create a health check servicer. We use the non-blocking implementation |
| # to avoid thread starvation. |
| health_servicer = health.HealthServicer( |
| experimental_non_blocking=True, |
| experimental_thread_pool=futures.ThreadPoolExecutor( |
| max_workers=_THREAD_POOL_SIZE)) |
| |
| # Create a tuple of all of the services we want to export via reflection. |
| services = tuple( |
| service.full_name |
| for service in helloworld_pb2.DESCRIPTOR.services_by_name.values()) + ( |
| reflection.SERVICE_NAME, health.SERVICE_NAME) |
| |
| # Mark all services as healthy. |
| health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server) |
| for service in services: |
| health_servicer.set(service, health_pb2.HealthCheckResponse.SERVING) |
| reflection.enable_server_reflection(services, server) |
| |
| |
| def _configure_greeter_server(server: grpc.Server, port: int, secure_mode: bool, |
| hostname) -> None: |
| # Add the application servicer to the server. |
| helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(hostname), server) |
| listen_address = f"{_LISTEN_HOST}:{port}" |
| if not secure_mode: |
| server.add_insecure_port(listen_address) |
| else: |
| # Use xDS credentials. |
| logger.info("Running with xDS Server credentials") |
| |
| # Fall back to insecure credentials. |
| server_fallback_creds = grpc.insecure_server_credentials() |
| server_creds = grpc.xds_server_credentials(server_fallback_creds) |
| server.add_secure_port(listen_address, server_creds) |
| |
| |
| def serve(port: int, hostname: str, maintenance_port: int, |
| secure_mode: bool) -> None: |
| if port == maintenance_port: |
| # If maintenance port and port are the same, start a single server. |
| server = grpc.server( |
| futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE)) |
| _configure_greeter_server(server, port, secure_mode, hostname) |
| _configure_maintenance_server(server, maintenance_port) |
| server.start() |
| logger.info("Greeter server listening on port %d", port) |
| logger.info("Maintenance server listening on port %d", maintenance_port) |
| server.wait_for_termination() |
| else: |
| # Otherwise, start two different servers. |
| greeter_server = grpc.server( |
| futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE), |
| xds=secure_mode) |
| _configure_greeter_server(greeter_server, port, secure_mode, hostname) |
| greeter_server.start() |
| logger.info("Greeter server listening on port %d", port) |
| maintenance_server = grpc.server( |
| futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE)) |
| _configure_maintenance_server(maintenance_server, maintenance_port) |
| maintenance_server.start() |
| logger.info("Maintenance server listening on port %d", maintenance_port) |
| greeter_server.wait_for_termination() |
| maintenance_server.wait_for_termination() |
| |
| |
| if __name__ == '__main__': |
| parser = argparse.ArgumentParser(description=_DESCRIPTION) |
| parser.add_argument("port", |
| default=50051, |
| type=int, |
| nargs="?", |
| help="The port on which to listen.") |
| parser.add_argument("hostname", |
| type=str, |
| default=None, |
| nargs="?", |
| help="The name clients will see in responses.") |
| parser.add_argument( |
| "--xds-creds", |
| action="store_true", |
| help="If specified, uses xDS credentials to connect to the server.") |
| args = parser.parse_args() |
| logging.basicConfig() |
| logger.setLevel(logging.INFO) |
| serve(args.port, args.hostname, args.port + 1, args.xds_creds) |