def call_kraken(self, request_type, request, instance, krakens_call): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ # TODO: handle min_alternative_journeys # TODO: call first bss|bss and do not call walking|walking if no bss in first results resp = [] logger = logging.getLogger(__name__) for dep_mode, arr_mode in krakens_call: pb_request = create_pb_request(request_type, request, dep_mode, arr_mode) self.nb_kraken_calls += 1 local_resp = instance.send_and_receive(pb_request) # for log purpose we put and id in each journeys for idx, j in enumerate(local_resp.journeys): j.internal_id = "{resp}-{j}".format(resp=self.nb_kraken_calls, j=idx) resp.append(local_resp) logger.debug("for mode %s|%s we have found %s journeys", dep_mode, arr_mode, len(local_resp.journeys)) for r in resp: fill_uris(r) return resp
def call_kraken(self, request_type, request, instance, krakens_call): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ # TODO: handle min_alternative_journeys # TODO: call first bss|bss and do not call walking|walking if no bss in first results resp = [] logger = logging.getLogger(__name__) futures = [] def worker(dep_mode, arr_mode, instance, request, request_id): return (dep_mode, arr_mode, instance.send_and_receive(request, request_id=request_id)) pool = gevent.pool.Pool(app.config.get('GREENLET_POOL_SIZE', 3)) for dep_mode, arr_mode in krakens_call: pb_request = create_pb_request(request_type, request, dep_mode, arr_mode) #we spawn a new green thread, it won't have access to our thread local request object so we set request_id futures.append(pool.spawn(worker, dep_mode, arr_mode, instance, pb_request, request_id=flask.request.id)) for future in gevent.iwait(futures): dep_mode, arr_mode, local_resp = future.get() # for log purpose we put and id in each journeys self.nb_kraken_calls += 1 for idx, j in enumerate(local_resp.journeys): j.internal_id = "{resp}-{j}".format(resp=self.nb_kraken_calls, j=idx) if 'ridesharing' in dep_mode or 'ridesharing' in arr_mode: _switch_back_to_ridesharing(local_resp) fill_uris(local_resp) resp.append(local_resp) logger.debug("for mode %s|%s we have found %s journeys", dep_mode, arr_mode, len(local_resp.journeys)) return resp
def call_kraken(self, request_type, request, instance, krakens_call, context=None): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ # TODO: handle min_alternative_journeys # TODO: call first bss|bss and do not call walking|walking if no bss in first results record_custom_parameter('scenario', 'new_default') resp = [] logger = logging.getLogger(__name__) futures = [] reqctx = copy_flask_request_context() def worker(dep_mode, arr_mode, instance, request, flask_request_id): with copy_context_in_greenlet_stack(reqctx): return ( dep_mode, arr_mode, instance.send_and_receive( request, flask_request_id=flask_request_id), ) pool = gevent.pool.Pool(app.config.get('GREENLET_POOL_SIZE', 3)) for dep_mode, arr_mode, direct_path_type in krakens_call: pb_request = create_pb_request(request_type, request, dep_mode, arr_mode, direct_path_type) # we spawn a new greenlet, it won't have access to our thread local request object so we pass the request_id futures.append( pool.spawn(worker, dep_mode, arr_mode, instance, pb_request, flask_request_id=flask.request.id)) for future in gevent.iwait(futures): dep_mode, arr_mode, local_resp = future.get() # for log purpose we put and id in each journeys self.nb_kraken_calls += 1 for idx, j in enumerate(local_resp.journeys): j.internal_id = "{resp}-{j}".format(resp=self.nb_kraken_calls, j=idx) if dep_mode == 'ridesharing': switch_back_to_ridesharing(local_resp, True) if arr_mode == 'ridesharing': switch_back_to_ridesharing(local_resp, False) fill_uris(local_resp) resp.append(local_resp) logger.debug("for mode %s|%s we have found %s journeys", dep_mode, arr_mode, len(local_resp.journeys)) return resp
def call_kraken(self, req, instance, tag=None): resp = None """ for all combinaison of departure and arrival mode we call kraken """ logger = logging.getLogger(__name__) # filter walking if bss in mode ? for o_mode, d_mode in itertools.product(self.origin_modes, self.destination_modes): req.journeys.streetnetwork_params.origin_mode = o_mode req.journeys.streetnetwork_params.destination_mode = d_mode local_resp = instance.send_and_receive(req) if local_resp.response_type == response_pb2.ITINERARY_FOUND: # if a specific tag was provided, we tag the journeys # and we don't call the qualifier, it will be done after # with the journeys from the previous query if tag: for j in local_resp.journeys: j.type = tag else: #we qualify the journeys request_type = "arrival" if req.journeys.clockwise else "departure" qualifier_one(local_resp.journeys, request_type) if not resp: resp = local_resp else: self.merge_response(resp, local_resp) if not resp: resp = local_resp logger.debug("for mode %s|%s we have found %s journeys: %s", o_mode, d_mode, len(local_resp.journeys), [j.type for j in local_resp.journeys]) fill_uris(resp) return resp
def call_kraken(self, request_type, request, instance, krakens_call): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ logger = logging.getLogger(__name__) logger.debug('datetime: %s', request['datetime']) for dep_mode, arr_mode in krakens_call: if dep_mode not in g.origins_fallback: g.origins_fallback[dep_mode] = instance.georef.get_stop_points(request['origin'], dep_mode, get_max_fallback_duration(request, dep_mode)) #logger.debug('origins %s: %s', dep_mode, g.origins_fallback[dep_mode]) if arr_mode not in g.destinations_fallback: g.destinations_fallback[arr_mode] = instance.georef.get_stop_points(request['destination'], arr_mode, get_max_fallback_duration(request, arr_mode), reverse=True) #logger.debug('destinations %s: %s', arr_mode, g.destinations_fallback[arr_mode]) if not g.requested_origin: g.requested_origin = instance.georef.place(request['origin']) if not g.requested_destination: g.requested_destination = instance.georef.place(request['destination']) resp = [] journey_parameters = create_parameters(request) for dep_mode, arr_mode in krakens_call: #todo: this is probably shared between multiple thread self.nb_kraken_calls += 1 local_resp = instance.planner.journeys(g.origins_fallback[dep_mode], g.destinations_fallback[arr_mode], request['datetime'], request['clockwise'], journey_parameters) # for log purpose we put and id in each journeys for idx, j in enumerate(local_resp.journeys): j.internal_id = "{resp}-{j}".format(resp=self.nb_kraken_calls, j=idx) for journey in local_resp.journeys: build_journey(journey, g.requested_origin, g.requested_destination, g.origins_fallback[dep_mode], g.destinations_fallback[arr_mode]) resp.append(local_resp) logger.debug("for mode %s|%s we have found %s journeys", dep_mode, arr_mode, len(local_resp.journeys)) for r in resp: fill_uris(r) return resp
def call_kraken(self, req, instance, tag=None): resp = None """ for all combinaison of departure and arrival mode we call kraken """ logger = logging.getLogger(__name__) futures = [] def worker(o_mode, d_mode, instance, request, request_id): return (o_mode, d_mode, instance.send_and_receive(request, request_id=request_id)) pool = gevent.pool.Pool(current_app.config.get('GREENLET_POOL_SIZE', 3)) for o_mode, d_mode in itertools.product(self.origin_modes, self.destination_modes): #since we use multiple green thread we have to copy the request local_req = copy.deepcopy(req) local_req.journeys.streetnetwork_params.origin_mode = o_mode local_req.journeys.streetnetwork_params.destination_mode = d_mode if o_mode == 'car' or (is_admin(req.journeys.origin[0].place) and is_admin(req.journeys.destination[0].place)): # we don't want direct path for car or for admin to admin journeys req.journeys.streetnetwork_params.enable_direct_path = False else: req.journeys.streetnetwork_params.enable_direct_path = True futures.append(pool.spawn(worker, o_mode, d_mode, instance, local_req, request_id=flask.request.id)) for future in gevent.iwait(futures): o_mode, d_mode, local_resp = future.get() if local_resp.response_type == response_pb2.ITINERARY_FOUND: # if a specific tag was provided, we tag the journeys # and we don't call the qualifier, it will be done after # with the journeys from the previous query if tag: for j in local_resp.journeys: j.type = tag else: #we qualify the journeys request_type = "arrival" if req.journeys.clockwise else "departure" qualifier_one(local_resp.journeys, request_type) fill_uris(local_resp) if not resp: resp = local_resp else: self.merge_response(resp, local_resp) if not resp: resp = local_resp logger.debug("for mode %s|%s we have found %s journeys: %s", o_mode, d_mode, len(local_resp.journeys), [j.type for j in local_resp.journeys]) return resp
def _compute_all(future_manager, request, instance, krakens_call): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ logger = logging.getLogger(__name__) logger.debug('request datetime: %s', request['datetime']) requested_dep_modes = {mode for mode, _ in krakens_call} requested_arr_modes = {mode for _, mode in krakens_call} logger.debug('requesting places by uri orig: %s dest %s', request['origin'], request['destination']) requested_orig = PlaceByUri(future_manager=future_manager, instance=instance, uri=request['origin']) requested_dest = PlaceByUri(future_manager=future_manager, instance=instance, uri=request['destination']) requested_orig_obj = get_entry_point_or_raise(requested_orig, request['origin']) requested_dest_obj = get_entry_point_or_raise(requested_dest, request['destination']) streetnetwork_path_pool = StreetNetworkPathPool( future_manager=future_manager, instance=instance) period_extremity = PeriodExtremity(request['datetime'], request['clockwise']) # we launch direct path asynchronously for mode in requested_dep_modes: streetnetwork_path_pool.add_async_request( requested_orig_obj=requested_orig_obj, requested_dest_obj=requested_dest_obj, mode=mode, period_extremity=period_extremity, request=request, streetnetwork_path_type=StreetNetworkPathType.DIRECT) # if max_duration(time to pass in pt) is zero, there is no need to continue, # we return all direct path without pt if request['max_duration'] == 0: return [ streetnetwork_path_pool.wait_and_get( requested_orig_obj=requested_orig_obj, requested_dest_obj=requested_dest_obj, mode=mode, request=request, period_extremity=period_extremity, streetnetwork_path_type=StreetNetworkPathType.DIRECT) for mode in requested_dep_modes ] # We'd like to get the duration of a direct path to do some optimizations in ProximitiesByCrowflyPool and # FallbackDurationsPool. # Note :direct_paths_by_mode is a dict of mode vs future of a direct paths, this line is not blocking direct_paths_by_mode = streetnetwork_path_pool.get_all_direct_paths() orig_proximities_by_crowfly = ProximitiesByCrowflyPool( future_manager=future_manager, instance=instance, requested_place_obj=requested_orig_obj, modes=requested_dep_modes, request=request, direct_paths_by_mode=direct_paths_by_mode) dest_proximities_by_crowfly = ProximitiesByCrowflyPool( future_manager=future_manager, instance=instance, requested_place_obj=requested_dest_obj, modes=requested_arr_modes, request=request, direct_paths_by_mode=direct_paths_by_mode) orig_places_free_access = PlacesFreeAccess( future_manager=future_manager, instance=instance, requested_place_obj=requested_orig_obj) dest_places_free_access = PlacesFreeAccess( future_manager=future_manager, instance=instance, requested_place_obj=requested_dest_obj) orig_fallback_durations_pool = FallbackDurationsPool( future_manager=future_manager, instance=instance, requested_place_obj=requested_orig_obj, modes=requested_dep_modes, proximities_by_crowfly_pool=orig_proximities_by_crowfly, places_free_access=orig_places_free_access, direct_paths_by_mode=direct_paths_by_mode, request=request, direct_path_type=StreetNetworkPathType.BEGINNING_FALLBACK) dest_fallback_durations_pool = FallbackDurationsPool( future_manager=future_manager, instance=instance, requested_place_obj=requested_dest_obj, modes=requested_arr_modes, proximities_by_crowfly_pool=dest_proximities_by_crowfly, places_free_access=dest_places_free_access, direct_paths_by_mode=direct_paths_by_mode, request=request, direct_path_type=StreetNetworkPathType.ENDING_FALLBACK) pt_journey_pool = PtJourneyPool( future_manager=future_manager, instance=instance, requested_orig_obj=requested_orig_obj, requested_dest_obj=requested_dest_obj, streetnetwork_path_pool=streetnetwork_path_pool, krakens_call=krakens_call, orig_fallback_durations_pool=orig_fallback_durations_pool, dest_fallback_durations_pool=dest_fallback_durations_pool, request=request) completed_pt_journeys = wait_and_complete_pt_journey( future_manager=future_manager, requested_orig_obj=requested_orig_obj, requested_dest_obj=requested_dest_obj, pt_journey_pool=pt_journey_pool, streetnetwork_path_pool=streetnetwork_path_pool, orig_places_free_access=orig_places_free_access, dest_places_free_access=dest_places_free_access, orig_fallback_durations_pool=orig_fallback_durations_pool, dest_fallback_durations_pool=dest_fallback_durations_pool, request=request) # At the stage, all types of journeys have been computed thus we build the final result here res = [] for mode in requested_dep_modes: dp = direct_paths_by_mode.get(mode).wait_and_get() if getattr(dp, "journeys", None): res.append(dp) # completed_pt_journeys may contain None and res must be a list of protobuf journey res.extend((j for j in completed_pt_journeys if j)) check_final_results_or_raise(res, orig_fallback_durations_pool, dest_fallback_durations_pool) for r in res: fill_uris(r) return res
def _compute_all(self, future_manager, request, instance, krakens_call, context): """ For all krakens_call, call the kraken and aggregate the responses Note: the responses will only attach a crowfly section as a fallback. Street network will be done when calling finalise_journeys return the list of all responses """ logger = logging.getLogger(__name__) logger.debug('request datetime: %s', request['datetime']) requested_dep_modes = {mode for mode, _, _ in krakens_call} requested_arr_modes = {mode for _, mode, _ in krakens_call} if context.partial_response_is_empty: logger.debug('requesting places by uri orig: %s dest %s', request['origin'], request['destination']) context.requested_orig = PlaceByUri(future_manager=future_manager, instance=instance, uri=request['origin']) context.requested_dest = PlaceByUri(future_manager=future_manager, instance=instance, uri=request['destination']) context.requested_orig_obj = get_entry_point_or_raise( context.requested_orig, request['origin']) context.requested_dest_obj = get_entry_point_or_raise( context.requested_dest, request['destination']) context.streetnetwork_path_pool = StreetNetworkPathPool( future_manager=future_manager, instance=instance) period_extremity = PeriodExtremity(request['datetime'], request['clockwise']) for mode in requested_dep_modes: context.streetnetwork_path_pool.add_async_request( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, mode=mode, period_extremity=period_extremity, request=request, streetnetwork_path_type=StreetNetworkPathType.DIRECT, ) # if max_duration(time to pass in pt) is zero, there is no need to continue, # we return all direct path without pt if request['max_duration'] == 0: return [ context.streetnetwork_path_pool.wait_and_get( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, mode=mode, request=request, period_extremity=period_extremity, streetnetwork_path_type=StreetNetworkPathType.DIRECT, ) for mode in requested_dep_modes ] # We'd like to get the duration of a direct path to do some optimizations in ProximitiesByCrowflyPool and # FallbackDurationsPool. # Note :direct_paths_by_mode is a dict of mode vs future of a direct paths, this line is not blocking context.direct_paths_by_mode = context.streetnetwork_path_pool.get_all_direct_paths( ) context.orig_proximities_by_crowfly = ProximitiesByCrowflyPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_orig_obj, modes=requested_dep_modes, request=request, direct_paths_by_mode=context.direct_paths_by_mode, max_nb_crowfly_by_mode=request['max_nb_crowfly_by_mode'], ) context.dest_proximities_by_crowfly = ProximitiesByCrowflyPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_dest_obj, modes=requested_arr_modes, request=request, direct_paths_by_mode=context.direct_paths_by_mode, max_nb_crowfly_by_mode=request['max_nb_crowfly_by_mode'], ) context.orig_places_free_access = PlacesFreeAccess( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_orig_obj) context.dest_places_free_access = PlacesFreeAccess( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_dest_obj) context.orig_fallback_durations_pool = FallbackDurationsPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_orig_obj, modes=requested_dep_modes, proximities_by_crowfly_pool=context. orig_proximities_by_crowfly, places_free_access=context.orig_places_free_access, direct_paths_by_mode=context.direct_paths_by_mode, request=request, direct_path_type=StreetNetworkPathType.BEGINNING_FALLBACK, ) context.dest_fallback_durations_pool = FallbackDurationsPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_dest_obj, modes=requested_arr_modes, proximities_by_crowfly_pool=context. dest_proximities_by_crowfly, places_free_access=context.dest_places_free_access, direct_paths_by_mode=context.direct_paths_by_mode, request=request, direct_path_type=StreetNetworkPathType.ENDING_FALLBACK, ) pt_journey_pool = PtJourneyPool( future_manager=future_manager, instance=instance, requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, streetnetwork_path_pool=context.streetnetwork_path_pool, krakens_call=krakens_call, orig_fallback_durations_pool=context.orig_fallback_durations_pool, dest_fallback_durations_pool=context.dest_fallback_durations_pool, request=request, ) pt_journey_elements = wait_and_build_crowflies( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, pt_journey_pool=pt_journey_pool, has_valid_direct_paths=context.streetnetwork_path_pool. has_valid_direct_paths(), orig_places_free_access=context.orig_places_free_access, dest_places_free_acces=context.dest_places_free_access, orig_fallback_durations_pool=context.orig_fallback_durations_pool, dest_fallback_durations_pool=context.dest_fallback_durations_pool, ) context.journeys_to_modes.update( self._map_journeys_to_modes(pt_journey_elements)) # At the stage, all types of journeys have been computed thus we build the final result here res = [] if context.partial_response_is_empty: for mode in requested_dep_modes: dp = context.direct_paths_by_mode.get(mode).wait_and_get() if getattr(dp, "journeys", None): res.append(dp) # pt_journeys may contain None and res must be a list of protobuf journey res.extend( (j.pt_journeys for j in pt_journey_elements if j.pt_journeys)) check_final_results_or_raise(res, context.orig_fallback_durations_pool, context.dest_fallback_durations_pool) for r in res: fill_uris(r) context.partial_response_is_empty = False return res
def _compute_isochrone_common(self, future_manager, request, instance, krakens_call, request_type): logger = logging.getLogger(__name__) logger.debug('request datetime: %s', request['datetime']) isochrone_center = request['origin'] or request['destination'] mode_getter = operator.itemgetter(0 if request['origin'] else 1) requested_modes = {mode_getter(call) for call in krakens_call} logger.debug('requesting places by uri orig: %s', isochrone_center) requested_orig = PlaceByUri(future_manager=future_manager, instance=instance, uri=isochrone_center) requested_obj = get_entry_point_or_raise(requested_orig, isochrone_center) direct_paths_by_mode = {} proximities_by_crowfly = ProximitiesByCrowflyPool( future_manager=future_manager, instance=instance, requested_place_obj=requested_obj, modes=requested_modes, request=request, direct_paths_by_mode=direct_paths_by_mode, max_nb_crowfly_by_mode=request.get('max_nb_crowfly_by_mode', {}), ) places_free_access = PlacesFreeAccess( future_manager=future_manager, instance=instance, requested_place_obj=requested_obj) direct_path_type = (StreetNetworkPathType.BEGINNING_FALLBACK if request['origin'] else StreetNetworkPathType.ENDING_FALLBACK) fallback_durations_pool = FallbackDurationsPool( future_manager=future_manager, instance=instance, requested_place_obj=requested_obj, modes=requested_modes, proximities_by_crowfly_pool=proximities_by_crowfly, places_free_access=places_free_access, direct_paths_by_mode=direct_paths_by_mode, request=request, direct_path_type=direct_path_type, ) # We don't need requested_orig_obj or requested_dest_obj for isochrone pt_journey_args = { "future_manager": future_manager, "instance": instance, "requested_orig_obj": None, "requested_dest_obj": None, "streetnetwork_path_pool": None, "krakens_call": krakens_call, "request": request, "request_type": request_type, "isochrone_center": isochrone_center, } if request['origin']: pt_journey_args.update({ "orig_fallback_durations_pool": fallback_durations_pool, "dest_fallback_durations_pool": None }) else: pt_journey_args.update({ "orig_fallback_durations_pool": None, "dest_fallback_durations_pool": fallback_durations_pool }) pt_journey_pool = PtJourneyPool(**pt_journey_args) res = [] for (dep_mode, arr_mode, future_pt_journey) in pt_journey_pool: logger.debug( "waiting for pt journey starts with %s and ends with %s", dep_mode, arr_mode) pt_journeys = wait_and_get_pt_journeys(future_pt_journey, False) if pt_journeys: res.append(pt_journeys) for r in res: fill_uris(r) # Graphical isochrone returns one response, not a list of responses if request_type == type_pb2.graphical_isochrone: return res[0] return res
def call_kraken(self, request_type, request, instance, krakens_call): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ logger = logging.getLogger(__name__) logger.debug('datetime: %s', request['datetime']) for dep_mode, arr_mode in krakens_call: if dep_mode not in g.origins_fallback: g.origins_fallback[dep_mode] = instance.georef.get_stop_points(request['origin'], dep_mode, get_max_fallback_duration(request, dep_mode)) #logger.debug('origins %s: %s', dep_mode, g.origins_fallback[dep_mode]) if arr_mode not in g.destinations_fallback: g.destinations_fallback[arr_mode] = instance.georef.get_stop_points(request['destination'], arr_mode, get_max_fallback_duration(request, arr_mode), reverse=True) #logger.debug('destinations %s: %s', arr_mode, g.destinations_fallback[arr_mode]) if not g.requested_origin: g.requested_origin = instance.georef.place(request['origin']) if not g.requested_destination: g.requested_destination = instance.georef.place(request['destination']) resp = [] journey_parameters = create_parameters(request) for dep_mode, arr_mode in krakens_call: #todo: this is probably shared between multiple thread self.nb_kraken_calls += 1 direct_path = self._get_direct_path(instance, dep_mode, g.requested_origin, g.requested_destination, request['datetime'], request['clockwise']) if direct_path.journeys: journey_parameters.direct_path_duration = direct_path.journeys[0].durations.total resp.append(direct_path) else: journey_parameters.direct_path_duration = None local_resp = instance.planner.journeys(g.origins_fallback[dep_mode], g.destinations_fallback[arr_mode], request['datetime'], request['clockwise'], journey_parameters) if local_resp.HasField(b"error") and local_resp.error.id == response_pb2.Error.error_id.Value('no_solution') \ and direct_path.journeys: local_resp.ClearField(b"error") if local_resp.HasField(b"error"): return [local_resp] # for log purpose we put and id in each journeys for idx, j in enumerate(local_resp.journeys): j.internal_id = "{resp}-{j}".format(resp=self.nb_kraken_calls, j=idx) for journey in local_resp.journeys: build_journey(journey, g.requested_origin, g.requested_destination, g.origins_fallback[dep_mode], g.destinations_fallback[arr_mode]) resp.append(local_resp) logger.debug("for mode %s|%s we have found %s journeys", dep_mode, arr_mode, len(local_resp.journeys)) logger.debug("for mode %s|%s we have found %s direct path", dep_mode, arr_mode, len(direct_path.journeys)) for r in resp: fill_uris(r) return resp
def _compute_journeys(self, future_manager, request, instance, krakens_call, context, request_type): """ For all krakens_call, call the kraken and aggregate the responses Note: the responses will only attach a crowfly section as a fallback. Street network will be done when calling finalise_journeys return the list of all responses """ logger = logging.getLogger(__name__) logger.debug('request datetime: %s', request['datetime']) request_id = request["request_id"] logger.debug("request_id : {}".format(request_id)) requested_dep_modes_with_pt = { mode for mode, _, direct_path_type in krakens_call if not self.is_type_only(direct_path_type) } requested_arr_modes_with_pt = { mode for _, mode, direct_path_type in krakens_call if not self.is_type_only(direct_path_type) } # These are the modes in first_section_modes[] and direct_path_modes[] # We need to compute direct_paths for them either because we requested it with direct_path_modes[] # Or because we need them to optimize the pt_journey computation requested_direct_path_modes = { mode for mode, _, direct_path_type in krakens_call if self.is_type_only(direct_path_type) } requested_direct_path_modes.update(requested_dep_modes_with_pt) if context.partial_response_is_empty: logger.debug('requesting places by uri orig: %s dest %s', request['origin'], request['destination']) context.requested_orig = PlaceByUri( future_manager=future_manager, instance=instance, uri=request['origin'], request_id="{}_place_origin".format(request_id), ) context.requested_dest = PlaceByUri( future_manager=future_manager, instance=instance, uri=request['destination'], request_id="{}_place_dest".format(request_id), ) context.requested_orig_obj = get_entry_point_or_raise(context.requested_orig, request['origin']) context.requested_dest_obj = get_entry_point_or_raise(context.requested_dest, request['destination']) context.streetnetwork_path_pool = StreetNetworkPathPool( future_manager=future_manager, instance=instance ) period_extremity = PeriodExtremity(request['datetime'], request['clockwise']) for mode in requested_direct_path_modes: context.streetnetwork_path_pool.add_async_request( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, mode=mode, period_extremity=period_extremity, request=request, streetnetwork_path_type=StreetNetworkPathType.DIRECT, request_id="{}_direct_path_mode_{}".format(request_id, mode), ) # if public transport is not requested, there is no need to continue, # we return all direct path without pt if request['max_duration'] == 0 or request.get('direct_path', "") in ( "only", "only_with_alternatives", ): res = [ context.streetnetwork_path_pool.wait_and_get( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, mode=mode, request=request, period_extremity=period_extremity, streetnetwork_path_type=StreetNetworkPathType.DIRECT, ) for mode in requested_direct_path_modes ] # add SN feed publishers context.streetnetwork_path_pool.add_feed_publishers(request, requested_direct_path_modes, res) return res # We'd like to get the duration of a direct path to do some optimizations in ProximitiesByCrowflyPool and # FallbackDurationsPool. # Note :direct_paths_by_mode is a dict of mode vs future of a direct paths, this line is not blocking context.direct_paths_by_mode = context.streetnetwork_path_pool.get_all_direct_paths() crowfly_distance = crowfly_distance_between( get_pt_object_coord(context.requested_orig_obj), get_pt_object_coord(context.requested_dest_obj) ) context.orig_proximities_by_crowfly = ProximitiesByCrowflyPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_orig_obj, modes=requested_dep_modes_with_pt, request=request, direct_paths_by_mode=context.direct_paths_by_mode, max_nb_crowfly_by_mode=request['max_nb_crowfly_by_mode'], request_id="{}_crowfly_orig".format(request_id), o_d_crowfly_distance=crowfly_distance, ) context.dest_proximities_by_crowfly = ProximitiesByCrowflyPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_dest_obj, modes=requested_arr_modes_with_pt, request=request, direct_paths_by_mode=context.direct_paths_by_mode, max_nb_crowfly_by_mode=request['max_nb_crowfly_by_mode'], request_id="{}_crowfly_dest".format(request_id), o_d_crowfly_distance=crowfly_distance, ) context.orig_places_free_access = PlacesFreeAccess( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_orig_obj, request_id="{}_places_free_access_orig".format(request_id), ) context.dest_places_free_access = PlacesFreeAccess( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_dest_obj, request_id="{}_places_free_access_dest".format(request_id), ) context.orig_fallback_durations_pool = FallbackDurationsPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_orig_obj, modes=requested_dep_modes_with_pt, proximities_by_crowfly_pool=context.orig_proximities_by_crowfly, places_free_access=context.orig_places_free_access, direct_paths_by_mode=context.direct_paths_by_mode, request=request, direct_path_type=StreetNetworkPathType.BEGINNING_FALLBACK, request_id="{}_fallback_orig".format(request_id), ) context.dest_fallback_durations_pool = FallbackDurationsPool( future_manager=future_manager, instance=instance, requested_place_obj=context.requested_dest_obj, modes=requested_arr_modes_with_pt, proximities_by_crowfly_pool=context.dest_proximities_by_crowfly, places_free_access=context.dest_places_free_access, direct_paths_by_mode=context.direct_paths_by_mode, request=request, direct_path_type=StreetNetworkPathType.ENDING_FALLBACK, request_id="{}_fallback_dest".format(request_id), ) pt_journey_pool = PtJourneyPool( future_manager=future_manager, instance=instance, requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, streetnetwork_path_pool=context.streetnetwork_path_pool, krakens_call=krakens_call, orig_fallback_durations_pool=context.orig_fallback_durations_pool, dest_fallback_durations_pool=context.dest_fallback_durations_pool, request=request, request_type=request_type, request_id="{}_ptjourney".format(request_id), ) pt_journey_elements = wait_and_build_crowflies( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, pt_journey_pool=pt_journey_pool, has_valid_direct_paths=context.streetnetwork_path_pool.has_valid_direct_paths(), orig_places_free_access=context.orig_places_free_access, dest_places_free_acces=context.dest_places_free_access, orig_fallback_durations_pool=context.orig_fallback_durations_pool, dest_fallback_durations_pool=context.dest_fallback_durations_pool, ) context.journeys_to_modes.update(self._map_journeys_to_modes(pt_journey_elements)) # At the stage, all types of journeys have been computed thus we build the final result here res = [] if context.partial_response_is_empty: for mode in requested_direct_path_modes: dp = context.direct_paths_by_mode.get(mode).wait_and_get() if getattr(dp, "journeys", None): res.append(dp) # pt_journeys may contain None and res must be a list of protobuf journey res.extend((j.pt_journeys for j in pt_journey_elements if j.pt_journeys)) check_final_results_or_raise( res, context.orig_fallback_durations_pool, context.dest_fallback_durations_pool ) for r in res: fill_uris(r) context.partial_response_is_empty = False # add SN feed publishers context.streetnetwork_path_pool.add_feed_publishers(request, requested_direct_path_modes, res) return res
def call_kraken(self, request_type, request, instance, krakens_call): """ For all krakens_call, call the kraken and aggregate the responses return the list of all responses """ logger = logging.getLogger(__name__) logger.debug('datetime: %s', request['datetime']) # odt_stop_points is a set of stop_point.uri with is_zonal = true used to manage tad_zonal odt_stop_points = set() # crowfly_stop_points is a set of stop_point.uri used to create a crowfly section. crowfly_stop_points = set() if not g.requested_origin: g.requested_origin = instance.georef.place(request['origin']) if not g.requested_origin: r = self._make_error_response( "The entry point: {} is not valid".format( request['origin']), response_pb2.Error.unknown_object) return [r] if not g.requested_destination: g.requested_destination = instance.georef.place( request['destination']) if not g.requested_destination: r = self._make_error_response( "The entry point: {} is not valid".format( request['destination']), response_pb2.Error.unknown_object) return [r] worker = AsyncWorker(instance, krakens_call, request) resp = [] # Now we compute the direct path with all requested departure # mode their time will be used to initialized our PT calls and # to bound the fallback duration of the first section. futures = worker.get_direct_path_futures( g.fallback_direct_path, g.requested_origin, g.requested_destination, request['datetime'], request['clockwise'], False, {mode for mode, _ in krakens_call}) for future in gevent.iwait(futures): resp_key, resp_direct_path = future.get() g.fallback_direct_path[resp_key] = resp_direct_path if resp_direct_path.journeys: resp_direct_path.journeys[0].internal_id = str(generate_id()) resp.append(resp_direct_path) if request.get('max_duration', 0): direct_path_duration_by_mode = make_direct_path_duration_by_mode( g.fallback_direct_path) # Get all stop_points around the requested origin within a crowfly range # Calls on origins and destinations are asynchronous orig_futures, dest_futures = worker.get_crowfly_futures( g.requested_origin, g.requested_destination, direct_path_duration_by_mode) gevent.joinall(orig_futures + dest_futures) for future in orig_futures: g.origins_places_crowfly.update(future.get()) for future in dest_futures: g.destinations_places_crowfly.update(future.get()) # Once we get crow fly stop points with origins and destinations, we start # the computation NM: the fallback matrix which contains the arrival duration for crowfly stop_points # from origin/destination # Ex: # stop_point1 stop_point2 stop_point3 # request_origin_1 86400(s) 43200(s) 21600(s) # As a side note this won't work the day when our ETA will be impacted by the datetime of the journey, # at least for the arrival when doing a "departure after" request. orig_futures, dest_futures = worker.get_routing_matrix_futures( g.requested_origin, g.requested_destination, g.origins_places_crowfly, g.destinations_places_crowfly, direct_path_duration_by_mode) gevent.joinall(orig_futures + dest_futures) for future in orig_futures: g.origins_fallback.update(future.get()) for future in dest_futures: g.destinations_fallback.update(future.get()) # In Some special cases, like "odt" or "departure(arrive) from(to) a stop_area", # the first(last) section should be treated differently orig_futures, dest_futures = worker.get_update_crowfly_duration_futures( ) gevent.joinall(orig_futures + dest_futures) def _updater(_futures, fb, crowfly_stop_points, odt_stop_points): for f in _futures: crowfly_res, odt_res, fb_res = f.get() crowfly_stop_points |= crowfly_res odt_stop_points |= odt_res for mode in (mode for mode in fb_res if mode in fb): fb.merge_reached_values(mode, fb_res[mode]) _updater(orig_futures, g.origins_fallback, crowfly_stop_points, odt_stop_points) _updater(dest_futures, g.destinations_fallback, crowfly_stop_points, odt_stop_points) # We update the fallback duration matrix if the requested origin/destination is also # present in the fallback duration matrix, which means from stop_point_1 to itself, it takes 0 second # Ex: # stop_point1 stop_point2 stop_point3 # stop_point_1 0(s) ... ... for dep_mode, arr_mode in krakens_call: g.origins_fallback.reset_if_exist(dep_mode, g.requested_origin.uri) g.destinations_fallback.reset_if_exist( arr_mode, g.requested_destination.uri) # Here starts the computation for pt journey journey_parameters = create_parameters(request) futures = worker.get_pt_journey_futures(g.requested_origin, g.requested_destination, g.fallback_direct_path, g.origins_fallback, g.destinations_fallback, journey_parameters) response_tuples = [] for future in gevent.iwait(futures): dep_mode, arr_mode, local_resp = future.get() if local_resp is None: continue dp_key = make_direct_path_key(dep_mode, g.requested_origin.uri, g.requested_destination.uri, request['datetime'], request['clockwise'], False) direct_path = g.fallback_direct_path.get(dp_key) if local_resp.HasField(b"error") and local_resp.error.id == response_pb2.Error.error_id.Value('no_solution') \ and direct_path.journeys: local_resp.ClearField(b"error") if local_resp.HasField(b"error"): #Here needs to modify error message of no_solution if len(g.origins_fallback[dep_mode]) == 0: self.update_error_message(local_resp, response_pb2.Error.no_origin, "no origin point") elif len(g.destinations_fallback[arr_mode]) == 0: self.update_error_message( local_resp, response_pb2.Error.no_destination, "no destination point") return [local_resp] # for log purpose we put and id in each journeys for j in local_resp.journeys: j.internal_id = str(generate_id()) response_tuples.append((dep_mode, arr_mode, j)) resp.append(local_resp) # Once the pt journey is found, we need to reconstruct the whole journey with fallback regarding the mode # For the sake of performance, we compute at first all fallback direct path asynchronously # then we update the pool of direct paths futures = worker.get_fallback_direct_path_futures( response_tuples, crowfly_stop_points, odt_stop_points) for future in gevent.iwait(futures): resp_key, resp_direct_path = future.get() g.fallback_direct_path[resp_key] = resp_direct_path # Now we construct the whole journey by concatenating the fallback direct path with the pt journey worker.build_journeys(response_tuples, crowfly_stop_points, odt_stop_points) #If resp doesn't contain any response we have to add an error message if len(resp) == 0: if len(g.origins_fallback[dep_mode]) == 0 and len( g.destinations_fallback[arr_mode]) == 0: resp.append( self._make_error_response( "no origin point nor destination point", response_pb2.Error.no_origin_nor_destination)) elif len(g.origins_fallback[dep_mode]) == 0: resp.append( self._make_error_response("no origin point", response_pb2.Error.no_origin)) elif len(g.destinations_fallback[arr_mode]) == 0: resp.append( self._make_error_response( "no destination point", response_pb2.Error.no_destination)) return resp for r in resp: fill_uris(r) return resp