Commit 11a69c44 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Context component:

- Migrated to use new generic gRPC servicer
- Migrated to use new generic Rest servicer
- Migrated to use new settings framework
parent 5dc77fe4
Loading
Loading
Loading
Loading
+0 −17
Original line number Diff line number Diff line
@@ -12,22 +12,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

# General settings
LOG_LEVEL = logging.INFO

# gRPC settings
GRPC_SERVICE_PORT = 1010
GRPC_MAX_WORKERS  = 200 # multiple clients might keep connections alive for Get*Events() RPC methods
GRPC_GRACE_PERIOD = 60

# REST-API settings
RESTAPI_SERVICE_PORT = 8080
RESTAPI_BASE_URL = '/api'

# Prometheus settings
METRICS_PORT = 9192

# Autopopulate the component with fake data for testing purposes?
POPULATE_FAKE_DATA = False
+8 −4
Original line number Diff line number Diff line
@@ -12,8 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Iterator
import grpc, logging
from typing import Iterator
from common.Constants import ServiceNameEnum
from common.Settings import get_service_host, get_service_port_grpc
from common.tools.client.RetryDecorator import retry, delay_exponential
from common.tools.grpc.Tools import grpc_message_to_json_string
from context.proto.context_pb2 import (
@@ -29,9 +31,11 @@ DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
RETRY_DECORATOR = retry(max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')

class ContextClient:
    def __init__(self, address, port):
        self.endpoint = '{:s}:{:s}'.format(str(address), str(port))
        LOGGER.debug('Creating channel to {:s}...'.format(self.endpoint))
    def __init__(self, host=None, port=None):
        if not host: host = get_service_host(ServiceNameEnum.CONTEXT)
        if not port: port = get_service_port_grpc(ServiceNameEnum.CONTEXT)
        self.endpoint = '{:s}:{:s}'.format(str(host), str(port))
        LOGGER.debug('Creating channel to {:s}...'.format(str(self.endpoint)))
        self.channel = None
        self.stub = None
        self.connect()
+2 −2
Original line number Diff line number Diff line
@@ -20,8 +20,8 @@ from context.tests.Objects import (
    LINK_R1_R2, LINK_R1_R2_ID, LINK_R1_R3, LINK_R1_R3_ID, LINK_R2_R3, LINK_R2_R3_ID, SERVICE_R1_R2, SERVICE_R1_R3,
    SERVICE_R2_R3)

def populate(address, port):
    client = ContextClient(address=address, port=port)
def populate(host=None, port=None):
    client = ContextClient(host=host, port=port)

    client.SetContext(Context(**CONTEXT))
    client.SetTopology(Topology(**TOPOLOGY))
+10 −19
Original line number Diff line number Diff line
@@ -14,17 +14,15 @@

import logging, signal, sys, threading
from prometheus_client import start_http_server
from common.Settings import get_setting
from common.Settings import get_log_level, get_metrics_port, get_setting
from common.orm.Database import Database
from common.orm.Factory import get_database_backend
from common.message_broker.Factory import get_messagebroker_backend
from common.message_broker.MessageBroker import MessageBroker
from context.Config import (
    GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD, LOG_LEVEL, POPULATE_FAKE_DATA, RESTAPI_SERVICE_PORT,
    RESTAPI_BASE_URL, METRICS_PORT)
from context.Config import POPULATE_FAKE_DATA
from .grpc_server.ContextService import ContextService
from .rest_server.Resources import RESOURCES
from .rest_server.Server import Server
from .rest_server.RestServer import RestServer
from .Populate import populate

terminate = threading.Event()
@@ -37,16 +35,7 @@ def signal_handler(signal, frame): # pylint: disable=redefined-outer-name
def main():
    global LOGGER # pylint: disable=global-statement

    grpc_service_port    = get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC', default=GRPC_SERVICE_PORT   )
    max_workers          = get_setting('MAX_WORKERS',                      default=GRPC_MAX_WORKERS    )
    grace_period         = get_setting('GRACE_PERIOD',                     default=GRPC_GRACE_PERIOD   )
    log_level            = get_setting('LOG_LEVEL',                        default=LOG_LEVEL           )
    restapi_service_port = get_setting('CONTEXTSERVICE_SERVICE_PORT_HTTP', default=RESTAPI_SERVICE_PORT)
    restapi_base_url     = get_setting('RESTAPI_BASE_URL',                 default=RESTAPI_BASE_URL    )
    metrics_port         = get_setting('METRICS_PORT',                     default=METRICS_PORT        )
    populate_fake_data   = get_setting('POPULATE_FAKE_DATA',               default=POPULATE_FAKE_DATA  )
    if isinstance(populate_fake_data, str): populate_fake_data = (populate_fake_data.upper() in {'T', '1', 'TRUE'})

    log_level = get_log_level()
    logging.basicConfig(level=log_level)
    LOGGER = logging.getLogger(__name__)

@@ -56,6 +45,7 @@ def main():
    LOGGER.info('Starting...')

    # Start metrics server
    metrics_port = get_metrics_port()
    start_http_server(metrics_port)

    # Get database instance
@@ -65,18 +55,19 @@ def main():
    messagebroker = MessageBroker(get_messagebroker_backend())

    # Starting context service
    grpc_service = ContextService(
        database, messagebroker, port=grpc_service_port, max_workers=max_workers, grace_period=grace_period)
    grpc_service = ContextService(database, messagebroker)
    grpc_service.start()

    rest_server = Server(port=restapi_service_port, base_url=restapi_base_url)
    rest_server = RestServer()
    for endpoint_name, resource_class, resource_url in RESOURCES:
        rest_server.add_resource(resource_class, resource_url, endpoint=endpoint_name, resource_class_args=(database,))
    rest_server.start()

    populate_fake_data = get_setting('POPULATE_FAKE_DATA', default=POPULATE_FAKE_DATA)
    if isinstance(populate_fake_data, str): populate_fake_data = (populate_fake_data.upper() in {'T', '1', 'TRUE'})
    if populate_fake_data:
        LOGGER.info('Populating fake data...')
        populate('127.0.0.1', grpc_service_port)
        populate(host='127.0.0.1', port=grpc_service.bind_port)
        LOGGER.info('Fake Data populated')

    # Wait for Ctrl+C or termination signal
+13 −52
Original line number Diff line number Diff line
@@ -12,61 +12,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import grpc
import logging
from concurrent import futures
from grpc_health.v1.health import HealthServicer, OVERALL_HEALTH
from grpc_health.v1.health_pb2 import HealthCheckResponse
from grpc_health.v1.health_pb2_grpc import add_HealthServicer_to_server
from context.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD
from common.Constants import ServiceNameEnum
from common.Settings import get_service_port_grpc
from common.message_broker.MessageBroker import MessageBroker
from common.orm.Database import Database
from common.tools.service.GenericGrpcService import GenericGrpcService
from context.proto.context_pb2_grpc import add_ContextServiceServicer_to_server
from .ContextServiceServicerImpl import ContextServiceServicerImpl

BIND_ADDRESS = '0.0.0.0'
LOGGER = logging.getLogger(__name__)
# Custom gRPC settings
GRPC_MAX_WORKERS = 200 # multiple clients might keep connections alive for Get*Events() RPC methods

class ContextService:
    def __init__(
        self, database, messagebroker, address=BIND_ADDRESS, port=GRPC_SERVICE_PORT, max_workers=GRPC_MAX_WORKERS,
        grace_period=GRPC_GRACE_PERIOD):
class ContextService(GenericGrpcService):
    def __init__(self, database : Database, messagebroker : MessageBroker, cls_name: str = __name__) -> None:
        port = get_service_port_grpc(ServiceNameEnum.CONTEXT)
        super().__init__(port, max_workers=GRPC_MAX_WORKERS, cls_name=cls_name)
        self.context_servicer = ContextServiceServicerImpl(database, messagebroker)

        self.database = database
        self.messagebroker = messagebroker
        self.address = address
        self.port = port
        self.endpoint = None
        self.max_workers = max_workers
        self.grace_period = grace_period
        self.context_servicer = None
        self.health_servicer = None
        self.pool = None
        self.server = None

    def start(self):
        self.endpoint = '{:s}:{:s}'.format(str(self.address), str(self.port))
        LOGGER.info('Starting Service (tentative endpoint: {:s}, max_workers: {:s})...'.format(
            str(self.endpoint), str(self.max_workers)))

        self.pool = futures.ThreadPoolExecutor(max_workers=self.max_workers)
        self.server = grpc.server(self.pool) # , interceptors=(tracer_interceptor,))

        self.context_servicer = ContextServiceServicerImpl(self.database, self.messagebroker)
    def install_servicers(self):
        add_ContextServiceServicer_to_server(self.context_servicer, self.server)

        self.health_servicer = HealthServicer(
            experimental_non_blocking=True, experimental_thread_pool=futures.ThreadPoolExecutor(max_workers=1))
        add_HealthServicer_to_server(self.health_servicer, self.server)

        port = self.server.add_insecure_port(self.endpoint)
        self.endpoint = '{:s}:{:s}'.format(str(self.address), str(port))
        LOGGER.info('Listening on {:s}...'.format(str(self.endpoint)))
        self.server.start()
        self.health_servicer.set(OVERALL_HEALTH, HealthCheckResponse.SERVING) # pylint: disable=maybe-no-member

        LOGGER.debug('Service started')

    def stop(self):
        LOGGER.debug('Stopping service (grace period {:s} seconds)...'.format(str(self.grace_period)))
        self.health_servicer.enter_graceful_shutdown()
        self.server.stop(self.grace_period)
        LOGGER.debug('Service stopped')
Loading