Skip to content

Commit

Permalink
add new backends_status
Browse files Browse the repository at this point in the history
regroup

add request id

simplify response

update interface

add more infor

add test
  • Loading branch information
xlqian committed Dec 18, 2024
1 parent cb58914 commit 1eed67b
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 1 deletion.
3 changes: 2 additions & 1 deletion docker/run_jormungandr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ fi
if [ $monitor_processes -eq 1 ]
then
echo "!!!!!!!!!!!!!!!!!!!!! Start Jormungandr with monitoring service !!!!!!!!!!!!!!!!!!!!!"
uwsgi --cache2 $jormungandr_cache2 $max_requests --http :9090 --stats :5050 --lazy-apps --file $file & uwsgi --cache2 $monitor_cache2 --http :9091 --lazy-apps --file $file --processes 1 --listen 5
# JORMUNGANDR_IS_PUBLIC is set to True only for the use of /v1/backends_status
uwsgi --cache2 $jormungandr_cache2 $max_requests --http :9090 --stats :5050 --lazy-apps --file $file & JORMUNGANDR_IS_PUBLIC=True uwsgi --cache2 $monitor_cache2 --http :9091 --lazy-apps --file $file --processes 1 --listen 5
else
echo "!!!!!!!!!!!!!!!!!!!!! Start Jormungandr without monitoring service !!!!!!!!!!!!!!!!!!!!!"
uwsgi --cache2 $jormungandr_cache2 $max_requests --http :9090 --stats :5050 --lazy-apps --file $file
Expand Down
2 changes: 2 additions & 0 deletions source/jormungandr/jormungandr/default_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
3 changes: 3 additions & 0 deletions source/jormungandr/jormungandr/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
82 changes: 82 additions & 0 deletions source/jormungandr/jormungandr/interfaces/v1/backends_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
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 = {
'lokis': {},
'krakens': {},
'errors': [],
}

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, request_id='backend_status')
status = protobuf_to_dict(resp, use_enum_labels=True)
is_loaded = status.get('status', {}).get('loaded') is True
if not is_loaded:
return instance_name, pt_planner_type, status, 'data is not loaded'
return instance_name, pt_planner_type, status, 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, status, err = future.get()
found_err |= err is not None
if err:
response['errors'].append(
{'backend_type': pt_planner_type, 'backend_name': instance_name, 'error': err}
)

key = 'krakens' if pt_planner_type == 'kraken' else 'lokis'
status_ = status.get('status', {}) if status is not None else {}
response[key][instance_name] = {
'status': status_.get('status'),
'backend_version': status_.get('navitia_version'),
'start_date': status_.get('start_production_date'),
'end_date': status_.get('end_production_date'),
'loaded': status_.get('loaded'),
'last_load_at': status_.get('last_load_at'),
'last_load_status': status_.get('last_load_status'),
'is_realtime_loaded': status_.get('is_realtime_loaded'),
'last_rt_data_loaded': status_.get('last_rt_data_loaded'),
}

if found_err:
status_code = 503

return response, status_code
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = '<lon:lon>;<lat:lat>/'
coverage = '/coverage/'
region = coverage + '<region:region>/'
Expand Down
22 changes: 22 additions & 0 deletions source/jormungandr/tests/end_point_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,25 @@ def test_coord_without_region_shouldnt_call_places_nearby(self):
r1 = self.tester.get('v1/coverage/main_routing_test/coord/0.001077974378345651;0.0005839027882705609')
r2 = self.tester.get('v1/coord/0.001077974378345651;0.0005839027882705609')
assert r1.get_json()['address'] == r2.get_json()['address']

def test_backends_status(self):
json_response = self.query("/v1/backends_status")

assert len(json_response['lokis']) == 2
assert len(json_response['krakens']) == 2

for attribute in [
'status',
'backend_version',
'start_date',
'end_date',
'loaded',
'last_load_at',
'last_load_status',
'is_realtime_loaded',
'last_rt_data_loaded',
]:
assert attribute in json_response['lokis']['main_ptref_test']
assert attribute in json_response['krakens']['main_ptref_test']
assert attribute in json_response['lokis']['main_routing_test']
assert attribute in json_response['krakens']['main_routing_test']

0 comments on commit 1eed67b

Please sign in to comment.