Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Jormun - NAV-3444] fix multiple first and last sections #4325

Closed
wants to merge 45 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
09a73f8
add penality bike parking
princefr Nov 13, 2024
05554fd
change way of doing things
princefr Nov 28, 2024
585b0ec
revert to default changes
princefr Nov 28, 2024
3ca942f
add tests cases
princefr Nov 28, 2024
1f822bf
revert some changes
princefr Nov 28, 2024
d861cba
pre commit fix
princefr Nov 28, 2024
339bc84
adding bragi call
princefr Nov 28, 2024
0373c8e
adding walking time
princefr Dec 2, 2024
634d5c2
update navitia-proto version
princefr Dec 2, 2024
d2a47ba
add new proto version
princefr Dec 2, 2024
f2d6474
Add navitia-proto submodule
princefr Dec 2, 2024
7d57442
restore gitmodule
princefr Dec 2, 2024
71ca89e
restor routing
princefr Dec 2, 2024
32fc209
fix after reviews
princefr Dec 2, 2024
cbd50e9
remove unacessary code for park_mode
princefr Dec 2, 2024
5403945
reverting some code review changes that causes bugs
princefr Dec 2, 2024
9350cc7
adding integration tests
princefr Dec 2, 2024
363ed83
update park mode help reference
princefr Dec 3, 2024
8ac0f19
adding server_default
princefr Dec 3, 2024
68c8d50
update server default value
princefr Dec 3, 2024
3a6f5a2
fix multiple first and last sections
princefr Dec 3, 2024
c9d35e2
add tests and fix vias
princefr Dec 4, 2024
11efe4b
remove distance comment
princefr Dec 4, 2024
209b9d5
add tests
princefr Dec 4, 2024
328ce79
fix times and tests
princefr Dec 5, 2024
5bec3eb
max_bike_duration_to_pt fix and arrival time fix
princefr Dec 5, 2024
9b5f03f
max_bike duration
princefr Dec 5, 2024
0857387
fix different place type
princefr Dec 11, 2024
16e25e6
update protos
princefr Dec 11, 2024
d6a38df
fix instructions without adding parking instructions
princefr Dec 11, 2024
69f6e4b
change parameter from array to string
princefr Dec 11, 2024
11348ac
fix signe for arrival and max_bike_duration_to_pt
princefr Dec 11, 2024
1b00005
remove params and update helpers methods
princefr Dec 16, 2024
5b6bdd4
fixing departure times
princefr Dec 18, 2024
c31d11e
fix sign
princefr Dec 18, 2024
740497c
fix double function
princefr Dec 18, 2024
42065db
jormungandr: Fix geographic position address
kadhikari Nov 28, 2024
1470704
Formatting and adding comment
kadhikari Nov 29, 2024
72afa9f
Another formatting
kadhikari Nov 29, 2024
6d64a1e
Comments updated
kadhikari Nov 29, 2024
b9882e5
[jormun]: Fix request_datetime in ridesharing
kadhikari Nov 15, 2024
dbb0032
Formatting 1
kadhikari Nov 15, 2024
6490682
jormungandr: Update poi objects in journeys if active by configuration
kadhikari Dec 6, 2024
ce6df5a
Formatting
kadhikari Dec 6, 2024
0c9b299
add new backends_status
xlqian Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
11 changes: 11 additions & 0 deletions source/jormungandr/jormungandr/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,12 @@ def car_park_provider(self):
instance_db = self.get_models()
return get_value_or_default('car_park_provider', instance_db, self.name)

@property
def disruptions_on_poi(self):
# type: () -> bool
instance_db = self.get_models()
return get_value_or_default('disruptions_on_poi', instance_db, self.name)

@property
def max_additional_connections(self):
# type: () -> int
Expand Down Expand Up @@ -820,6 +826,8 @@ def additional_parameters(self):
additional_time_after_first_section_taxi = _make_property_getter('additional_time_after_first_section_taxi')
additional_time_before_last_section_taxi = _make_property_getter('additional_time_before_last_section_taxi')

on_street_bike_parking_duration = _make_property_getter('on_street_bike_parking_duration')

max_walking_direct_path_duration = _make_property_getter('max_walking_direct_path_duration')
max_bike_direct_path_duration = _make_property_getter('max_bike_direct_path_duration')
max_bss_direct_path_duration = _make_property_getter('max_bss_direct_path_duration')
Expand Down Expand Up @@ -865,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
55 changes: 43 additions & 12 deletions source/jormungandr/jormungandr/interfaces/v1/Journeys.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from jormungandr.interfaces.parsers import default_count_arg_type
from jormungandr.interfaces.v1.ResourceUri import complete_links
from functools import wraps
from jormungandr.park_modes import all_park_modes
from jormungandr.timezone import set_request_timezone
from jormungandr.interfaces.v1.make_links import (
create_external_link,
Expand Down Expand Up @@ -377,6 +378,14 @@ def get_disruption_uris(object):

return uris

def impact_on_poi():
for d in objects[0].get('disruptions', []):
for io in d.get('impacted_objects', []):
if io.get('pt_object', {}).get('embedded_type') == "poi":
return True

return False

def update_for_poi(object):
# Add links in poi object
object_copy = deepcopy(object)
Expand All @@ -388,22 +397,20 @@ def update_for_poi(object):
create_internal_link(_type="disruption", rel="disruptions", id=disruption_uri)
)

# We should only update 'from' object of the first section as well as 'to' object of the last one
# since object poi can only be present in those two cases
# If object is absent in first_section['from'] as well as last_section['to'] for the first journey
# then no need to verify for the remaining journeys
# If no disruption on poi exist, no action to do
if not impact_on_poi():
return objects

# We should update 'from' and 'to' object of all the sections if object is POI
for j in objects[0].get('journeys', []):
if "sections" not in j:
continue

first_sec = j['sections'][0]
last_sec = j['sections'][-1]
if first_sec['from']['embedded_type'] != "poi" and last_sec['to']['embedded_type'] != "poi":
break
if first_sec['from']['embedded_type'] == "poi":
update_for_poi(first_sec['from']['poi'])
if last_sec['to']['embedded_type'] == "poi":
update_for_poi(last_sec['to']['poi'])
for s in j.get('sections', []):
if s.get('from', {}).get('embedded_type') == "poi":
update_for_poi(s['from']['poi'])
if s.get('to', {}).get('embedded_type') == "poi":
update_for_poi(s['to']['poi'])

return objects

Expand Down Expand Up @@ -448,10 +455,27 @@ def wrapper(*args, **kwargs):
if g.origin_detail:
self.clean_global_origin_destination_detail(g.origin_detail)
j['sections'][0]['from'] = g.origin_detail

# Replace coord by origin position if present in g.request_origin
if hasattr(g, 'request_origin') and g.request_origin:
coord = j['sections'][0]['from'].get('address', {}).get('coord')
if coord:
j['sections'][0]['from']['address']['coord'] = g.request_origin.get('address').get(
'coord'
)

if g.destination_detail:
self.clean_global_origin_destination_detail(g.destination_detail)
j['sections'][-1]['to'] = g.destination_detail

# Replace coord by destination position if present in g.request_destination
if hasattr(g, 'request_destination') and g.request_destination:
coord = j['sections'][-1]['to'].get('address', {}).get('coord')
if coord:
j['sections'][-1]['to']['address']['coord'] = g.request_destination.get(
'address'
).get('coord')

return objects

return wrapper
Expand Down Expand Up @@ -544,6 +568,7 @@ def __init__(self):
help="Show more information about the poi if it's available, for instance, show "
"BSS/car park availability in the pois(BSS/car park) of response",
)

parser_get.add_argument(
"_no_shared_section",
type=BooleanType(),
Expand Down Expand Up @@ -826,6 +851,9 @@ def _set_specific_params(mod):
if args.get('additional_time_before_last_section_taxi') is None:
args['additional_time_before_last_section_taxi'] = mod.additional_time_before_last_section_taxi

if args.get("on_street_bike_parking_duration") is None:
args["on_street_bike_parking_duration"] = mod.on_street_bike_parking_duration

if args.get('_stop_points_nearby_duration') is None:
args['_stop_points_nearby_duration'] = mod.stop_points_nearby_duration

Expand Down Expand Up @@ -886,6 +914,9 @@ def _set_specific_params(mod):
if args.get('_use_predicted_traffic') is None:
args['_use_predicted_traffic'] = mod.use_predicted_traffic

if args.get('_disruptions_on_poi') is None:
args['_disruptions_on_poi'] = mod.disruptions_on_poi

# When computing 'same_journey_schedules'(is_journey_schedules=True), some parameters need to be overridden
# because they are contradictory to the request
if args.get("is_journey_schedules"):
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
28 changes: 27 additions & 1 deletion source/jormungandr/jormungandr/interfaces/v1/journey_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
# www.navitia.io

from __future__ import absolute_import, print_function, unicode_literals, division
from jormungandr import i_manager, fallback_modes, partner_services, app
from jormungandr import i_manager, fallback_modes, park_modes, partner_services, app
from jormungandr.interfaces.v1.ResourceUri import ResourceUri
from datetime import datetime
from jormungandr.resources_utils import ResourceUtc
Expand Down Expand Up @@ -239,6 +239,19 @@ def __init__(self, output_type_serializer):
action="append",
help='Same as first_section_mode but for the last section.',
)

parser_get.add_argument(
"park_mode",
type=OptionValue(park_modes.all_park_modes),
dest="park_mode",
help='Force the park mode for the first or last section of a journey\n'
'Need to be set with one of the first_section_mode[] or last_section_mode[] corresponding to vehicles that could be parked\n'
'Note: Only work with the first or last section mode being a bike for the moment\n'
'Eg: If you want to park a bike at the departure, you need:\n'
'`first_section_mode[]=bike&park_mode=on_street`'
'Eg: If you want to park a bike at the arrival, you need:\n'
'`last_section_mode[]=bike&park_mode=on_street`',
)
# for retrocompatibility purpose, we duplicate (without []):
parser_get.add_argument(
"first_section_mode",
Expand Down Expand Up @@ -381,6 +394,12 @@ def __init__(self, output_type_serializer):
'and thus avoid disrupted public transport.\n'
'Nota: `disruption_active=true` <=> `data_freshness=realtime`',
)
parser_get.add_argument(
"_disruptions_on_poi",
type=BooleanType(),
hidden=True,
help="Fetch and display disruptions on poi in the journey response",
)
# no default value for data_freshness because we need to maintain retrocomp with disruption_active
parser_get.add_argument(
"data_freshness",
Expand Down Expand Up @@ -506,6 +525,13 @@ def __init__(self, output_type_serializer):
type=int,
help="the additional time added to the taxi section, right before riding the taxi but after hopping off the public transit",
)

parser_get.add_argument(
"on_street_bike_parking_duration",
type=int,
help="the additional time added to the bike section before and after parking the bike",
)

parser_get.add_argument(
"_pt_planner",
type=OptionValue(['kraken', 'loki']),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class ParametersSerializer(serpy.Serializer):
max_extra_second_pass = Field(schema_type=int)
additional_time_after_first_section_taxi = Field(schema_type=int)
additional_time_before_last_section_taxi = Field(schema_type=int)
on_street_bike_parking_duration = Field(schema_type=int)
max_walking_direct_path_duration = Field(schema_type=int)
max_bike_direct_path_duration = Field(schema_type=int)
max_bss_direct_path_duration = Field(schema_type=int)
Expand Down
23 changes: 18 additions & 5 deletions source/jormungandr/jormungandr/interfaces/v1/test/journey_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def handle_poi_disruptions_test():
resp = get_response_with_poi_and_disruptions()
assert len(resp[0].get("journeys", 0)) == 2

# Journey 1: a disruption exist for poi_uri_a: the poi in journey should have links and
# Journey 1: a disruption exist for poi_uri_a (origin): the poi in journey should have links and
# impacted_object should have object poi
origin = resp[0].get("journeys", 0)[0]['sections'][0]['from']['poi']
assert origin['id'] == "poi_uri_a"
Expand All @@ -254,23 +254,36 @@ def handle_poi_disruptions_test():
assert impacted_object['id'] == "poi_uri_a"
assert "links" not in impacted_object

# No disruption exist for poi_uri_b: the poi in journey doesn't have links and object poi is absent
# No disruption exist for poi_uri_b (destination): the poi in journey doesn't have links and object poi is absent
# in impacted_object
destination = resp[0].get("journeys", 0)[0]['sections'][2]['to']['poi']
assert destination['id'] == "poi_uri_b"
assert len(destination["links"]) == 0

# Journey 2: a disruption exist for poi_uri_a: the poi in journey should have links and
# impacted_object should have object poi
# Journey 2: a disruption exist for poi_uri_a (origin) and another exist for poi_uri_from:
# both pois in journey should have links and impacted_object should have object poi
origin = resp[0].get("journeys", 0)[1]['sections'][0]['from']['poi']
assert origin['id'] == "poi_uri_a"
assert len(origin['links']) == 1
impacted_object = resp[0]['disruptions'][0]['impacted_objects'][0]['pt_object']['poi']
assert impacted_object['id'] == "poi_uri_a"
assert "links" not in impacted_object

sections = resp[0].get("journeys", 0)[1]['sections']
assert len(sections) == 3
poi = sections[0]['to']['poi']
assert poi['id'] == "poi_uri_from"
assert len(poi['links']) == 1
impacted_object = resp[0]['disruptions'][1]['impacted_objects'][0]['pt_object']['poi']
assert impacted_object['id'] == "poi_uri_from"
assert "links" not in impacted_object

poi = sections[1]['to']['poi']
assert poi['id'] == "poi_uri_to"
assert len(poi['links']) == 0

# No disruption exist for poi_uri_b: the poi in journey doesn't have links and object poi is absent
# in impacted_object
destination = resp[0].get("journeys", 0)[1]['sections'][0]['to']['poi']
destination = sections[2]['to']['poi']
assert destination['id'] == "poi_uri_b"
assert len(destination["links"]) == 0
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
Loading