Skip to content

Commit 2955b4d

Browse files
committed
add new backends_status
regroup add request id simplify response update interface add more infor add test
1 parent d389810 commit 2955b4d

File tree

6 files changed

+114
-1
lines changed

6 files changed

+114
-1
lines changed

docker/run_jormungandr.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ fi
6666
if [ $monitor_processes -eq 1 ]
6767
then
6868
echo "!!!!!!!!!!!!!!!!!!!!! Start Jormungandr with monitoring service !!!!!!!!!!!!!!!!!!!!!"
69-
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
69+
# JORMUNGANDR_IS_PUBLIC is set to True only for the use of /v1/backends_status
70+
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
7071
else
7172
echo "!!!!!!!!!!!!!!!!!!!!! Start Jormungandr without monitoring service !!!!!!!!!!!!!!!!!!!!!"
7273
uwsgi --cache2 $jormungandr_cache2 $max_requests --http :9090 --stats :5050 --lazy-apps --file $file

source/jormungandr/jormungandr/default_settings.py

+2
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,5 @@
412412

413413
USE_EXCLUDED_ZONES = boolean(os.getenv('JORMUNGANDR_USE_EXCLUDED_ZONES', False))
414414
ASGARD_S3_BUCKET = os.getenv('JORMUNGANDR_ASGARD_S3_BUCKET', '')
415+
416+
BACKENDS_STATUS_GREENLET_POOL_SIZE = os.getenv('JORMUNGANDR_BACKENDS_STATUS_GREENLET_POOL_SIZE', 10)

source/jormungandr/jormungandr/instance.py

+3
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,9 @@ def get_pt_planner(self, pt_planner_id=None):
865865
pt_planner_id = pt_planner_id or self.default_pt_planner
866866
return self._pt_planner_manager.get_pt_planner(pt_planner_id)
867867

868+
def get_all_pt_planners(self):
869+
return self._pt_planner_manager.get_all_pt_planners()
870+
868871
def get_pt_journey_fare(self, loki_pt_journey_fare_id=None):
869872
pt_journey_fare_id = loki_pt_journey_fare_id or self.loki_pt_journey_fare
870873
return self._pt_journey_fare_backend_manager.get_pt_journey_fare(pt_journey_fare_id)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
from jormungandr import i_manager
2+
from jormungandr.protobuf_to_dict import protobuf_to_dict
3+
from jormungandr.interfaces.v1.StatedResource import StatedResource
4+
from navitiacommon import type_pb2, request_pb2
5+
from jormungandr import exceptions
6+
from collections import defaultdict
7+
import gevent, gevent.pool
8+
from jormungandr import app
9+
10+
11+
class BackendsStatus(StatedResource):
12+
def __init__(self, *args, **kwargs):
13+
super().__init__(self, *args, **kwargs)
14+
15+
def get(self):
16+
regions = i_manager.get_regions()
17+
18+
response = {
19+
'lokis': {},
20+
'krakens': {},
21+
'errors': [],
22+
}
23+
24+
pool = gevent.pool.Pool(app.config.get('BACKENDS_STATUS_GREENLET_POOL_SIZE', 10))
25+
26+
def do(instance_name, pt_planner_type, pt_planner, req):
27+
try:
28+
resp = pt_planner.send_and_receive(req, request_id='backend_status')
29+
status = protobuf_to_dict(resp, use_enum_labels=True)
30+
is_loaded = status.get('status', {}).get('loaded') is True
31+
if not is_loaded:
32+
return instance_name, pt_planner_type, status, 'data is not loaded'
33+
return instance_name, pt_planner_type, status, None
34+
except exceptions.DeadSocketException as e:
35+
return (
36+
instance_name,
37+
pt_planner_type,
38+
None,
39+
'instance {} backend {} did not respond because: {}'.format(
40+
instance_name, pt_planner_type, str(e)
41+
),
42+
)
43+
44+
futures = []
45+
46+
req = request_pb2.Request()
47+
req.requested_api = type_pb2.STATUS
48+
49+
for key_region in regions:
50+
instance = i_manager.instances[key_region]
51+
for pt_planner_type, pt_planner in instance.get_all_pt_planners():
52+
futures.append(pool.spawn(do, instance.name, pt_planner_type, pt_planner, req))
53+
54+
found_err = False
55+
status_code = 200
56+
57+
for future in gevent.iwait(futures):
58+
instance_name, pt_planner_type, status, err = future.get()
59+
found_err |= err is not None
60+
if err:
61+
response['errors'].append(
62+
{'backend_type': pt_planner_type, 'backend_name': instance_name, 'error': err}
63+
)
64+
65+
key = 'krakens' if pt_planner_type == 'kraken' else 'lokis'
66+
status_ = status.get('status', {}) if status is not None else {}
67+
response[key][instance_name] = {
68+
'status': status_.get('status'),
69+
'backend_version': status_.get('navitia_version'),
70+
'start_date': status_.get('start_production_date'),
71+
'end_date': status_.get('end_production_date'),
72+
'loaded': status_.get('loaded'),
73+
'last_load_at': status_.get('last_load_at'),
74+
'last_load_status': status_.get('last_load_status'),
75+
'is_realtime_loaded': status_.get('is_realtime_loaded'),
76+
'last_rt_data_loaded': status_.get('last_rt_data_loaded'),
77+
}
78+
79+
if found_err:
80+
status_code = 503
81+
82+
return response, status_code

source/jormungandr/jormungandr/modules/v1_routing/v1_routing.py

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
users,
5555
opg_status,
5656
opg_excluded_zones,
57+
backends_status,
5758
)
5859
from werkzeug.routing import BaseConverter, FloatConverter, PathConverter
5960
from jormungandr.modules_loader import AModule
@@ -131,6 +132,8 @@ def setup(self):
131132
self.add_resource(Readyness.Readyness, '/readyness', endpoint='readyness')
132133
self.module_resources_manager.register_resource(Index.TechnicalStatus())
133134
self.add_resource(Index.TechnicalStatus, '/status', endpoint='technical_status')
135+
self.add_resource(backends_status.BackendsStatus, '/backends_status', endpoint='backends_status')
136+
134137
lon_lat = '<lon:lon>;<lat:lat>/'
135138
coverage = '/coverage/'
136139
region = coverage + '<region:region>/'

source/jormungandr/tests/end_point_tests.py

+22
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,25 @@ def test_coord_without_region_shouldnt_call_places_nearby(self):
258258
r1 = self.tester.get('v1/coverage/main_routing_test/coord/0.001077974378345651;0.0005839027882705609')
259259
r2 = self.tester.get('v1/coord/0.001077974378345651;0.0005839027882705609')
260260
assert r1.get_json()['address'] == r2.get_json()['address']
261+
262+
def test_backends_status(self):
263+
json_response = self.query("/v1/backends_status")
264+
265+
assert len(json_response['lokis']) == 2
266+
assert len(json_response['krakens']) == 2
267+
268+
for attribute in [
269+
'status',
270+
'backend_version',
271+
'start_date',
272+
'end_date',
273+
'loaded',
274+
'last_load_at',
275+
'last_load_status',
276+
'is_realtime_loaded',
277+
'last_rt_data_loaded',
278+
]:
279+
assert attribute in json_response['lokis']['main_ptref_test']
280+
assert attribute in json_response['krakens']['main_ptref_test']
281+
assert attribute in json_response['lokis']['main_routing_test']
282+
assert attribute in json_response['krakens']['main_routing_test']

0 commit comments

Comments
 (0)