diff --git a/source/jormungandr/jormungandr/default_settings.py b/source/jormungandr/jormungandr/default_settings.py index f6c773a581..3c136046cf 100644 --- a/source/jormungandr/jormungandr/default_settings.py +++ b/source/jormungandr/jormungandr/default_settings.py @@ -412,3 +412,5 @@ USE_EXCLUDED_ZONES = boolean(os.getenv('JORMUNGANDR_USE_EXCLUDED_ZONES', False)) ASGARD_S3_BUCKET = os.getenv('JORMUNGANDR_ASGARD_S3_BUCKET', '') + +BACKENDS_STATUS_GREENLET_POOL_SIZE = os.getenv('JORMUNGANDR_BACKENDS_STATUS_GREENLET_POOL_SIZE', 10) diff --git a/source/jormungandr/jormungandr/instance.py b/source/jormungandr/jormungandr/instance.py index ae665f125f..defb847cbc 100644 --- a/source/jormungandr/jormungandr/instance.py +++ b/source/jormungandr/jormungandr/instance.py @@ -873,6 +873,9 @@ def get_pt_planner(self, pt_planner_id=None): pt_planner_id = pt_planner_id or self.default_pt_planner return self._pt_planner_manager.get_pt_planner(pt_planner_id) + def get_all_pt_planners(self): + return self._pt_planner_manager.get_all_pt_planners() + def get_pt_journey_fare(self, loki_pt_journey_fare_id=None): pt_journey_fare_id = loki_pt_journey_fare_id or self.loki_pt_journey_fare return self._pt_journey_fare_backend_manager.get_pt_journey_fare(pt_journey_fare_id) diff --git a/source/jormungandr/jormungandr/interfaces/v1/backends_status.py b/source/jormungandr/jormungandr/interfaces/v1/backends_status.py new file mode 100644 index 0000000000..5c1823d409 --- /dev/null +++ b/source/jormungandr/jormungandr/interfaces/v1/backends_status.py @@ -0,0 +1,62 @@ +from jormungandr import i_manager +from jormungandr.protobuf_to_dict import protobuf_to_dict +from jormungandr.interfaces.v1.StatedResource import StatedResource +from navitiacommon import type_pb2, request_pb2 +from jormungandr import exceptions +from collections import defaultdict +import gevent, gevent.pool +from jormungandr import app + + +class BackendsStatus(StatedResource): + def __init__(self, *args, **kwargs): + super().__init__(self, *args, **kwargs) + + def get(self): + regions = i_manager.get_regions() + + response = defaultdict(list) + + pool = gevent.pool.Pool(app.config.get('BACKENDS_STATUS_GREENLET_POOL_SIZE', 10)) + + def do(instance_name, pt_planner_type, pt_planner, req): + try: + resp = pt_planner.send_and_receive(req) + raw_resp_dict = protobuf_to_dict(resp, use_enum_labels=True) + return instance_name, pt_planner_type, raw_resp_dict, None + except exceptions.DeadSocketException as e: + return ( + instance_name, + pt_planner_type, + None, + 'instance {} backend {} did not respond because: {}'.format( + instance_name, pt_planner_type, str(e) + ), + ) + + futures = [] + + req = request_pb2.Request() + req.requested_api = type_pb2.STATUS + + for key_region in regions: + instance = i_manager.instances[key_region] + for pt_planner_type, pt_planner in instance.get_all_pt_planners(): + futures.append(pool.spawn(do, instance.name, pt_planner_type, pt_planner, req)) + + found_err = False + status_code = 200 + + for future in gevent.iwait(futures): + instance_name, pt_planner_type, res, err = future.get() + found_err |= err is not None + response[pt_planner_type].append( + { + instance_name: res, + 'err': err, + } + ) + if found_err: + status_code = 503 + + return response, status_code diff --git a/source/jormungandr/jormungandr/modules/v1_routing/v1_routing.py b/source/jormungandr/jormungandr/modules/v1_routing/v1_routing.py index a4f86c8b64..fd2dfd85ed 100644 --- a/source/jormungandr/jormungandr/modules/v1_routing/v1_routing.py +++ b/source/jormungandr/jormungandr/modules/v1_routing/v1_routing.py @@ -54,6 +54,7 @@ users, opg_status, opg_excluded_zones, + backends_status, ) from werkzeug.routing import BaseConverter, FloatConverter, PathConverter from jormungandr.modules_loader import AModule @@ -131,6 +132,8 @@ def setup(self): self.add_resource(Readyness.Readyness, '/readyness', endpoint='readyness') self.module_resources_manager.register_resource(Index.TechnicalStatus()) self.add_resource(Index.TechnicalStatus, '/status', endpoint='technical_status') + self.add_resource(backends_status.BackendsStatus, '/backends_status', endpoint='backends_status') + lon_lat = ';/' coverage = '/coverage/' region = coverage + '/'