Exemplo n.º 1
0
    def _on_request(self, message):
        log = logging.getLogger(__name__)
        try:
            task = task_pb2.Task()
            try:
                # `body` is of unicode type, but we need str type for
                # `ParseFromString()` to work.  It seems to work.
                # Maybe kombu estimate that, without any information,
                # the body should be something as json, and thus a
                # unicode string.  On the c++ side, I didn't manage to
                # find a way to give a content-type or something like
                # that.
                body = str(message.payload)
                task.ParseFromString(body)
            except DecodeError as e:
                log.warn('invalid protobuf: {}'.format(str(e)))
                return

            log.info('Getting a full feed publication request', extra={'task': task})
            if task.action != task_pb2.LOAD_REALTIME or not task.load_realtime:
                return
            start_datetime = datetime.utcnow()
            begin_date = None
            end_date = None
            if hasattr(task.load_realtime, "begin_date"):
                if task.load_realtime.begin_date:
                    begin_date = str_to_date(task.load_realtime.begin_date)

            if hasattr(task.load_realtime, "end_date"):
                if task.load_realtime.end_date:
                    end_date = str_to_date(task.load_realtime.end_date)
            feed = convert_to_gtfsrt(TripUpdate.find_by_contributor_period(task.load_realtime.contributors,
                                                                           begin_date,
                                                                           end_date),
                                     gtfs_realtime_pb2.FeedHeader.FULL_DATASET)

            feed_str = feed.SerializeToString()
            log.info('Starting of full feed publication {}, {}'.format(len(feed_str), task), extra={'size': len(feed_str), 'task': task})
            # http://docs.celeryproject.org/projects/kombu/en/latest/userguide/producers.html#bypassing-routing-by-using-the-anon-exchange
            self.producer.publish(feed_str,
                                  routing_key=task.load_realtime.queue_name,
                                  retry=True,
                                  retry_policy={
                                      'interval_start': 0,  # First retry immediately,
                                      'interval_step': 2,   # then increase by 2s for every retry.
                                      'interval_max': 10,   # but don't exceed 10s between retries.
                                      'max_retries':  self.max_retries,     # give up after 10 (by default) tries.
                                      })
            duration = (datetime.utcnow() - start_datetime).total_seconds()
            log.info('End of full feed publication', extra={'duration': duration, 'task': task})
            record_call('Full feed publication', size=len(feed_str), routing_key=task.load_realtime.queue_name,
                        duration=duration, trip_update_count=len(feed.entity),
                        contributor=task.load_realtime.contributors)
        finally:
            db.session.remove()
Exemplo n.º 2
0
        def callback(body, message):
            try:
                task = task_pb2.Task()
                try:
                    # `body` is of unicode type, but we need str type for
                    # `ParseFromString()` to work.  It seems to work.
                    # Maybe kombu estimate that, without any information,
                    # the body should be something as json, and thus a
                    # unicode string.  On the c++ side, I didn't manage to
                    # find a way to give a content-type or something like
                    # that.
                    body = str(body)
                    task.ParseFromString(body)
                except DecodeError as e:
                    log.warn('invalid protobuf: {}'.format(str(e)))
                    return

                log.info('getting a request: {}'.format(task))
                if task.action != task_pb2.LOAD_REALTIME or not task.load_realtime:
                    return
                begin_date = None
                end_date = None
                if hasattr(task.load_realtime, "begin_date"):
                    if task.load_realtime.begin_date:
                        begin_date = str_to_date(task.load_realtime.begin_date)

                if hasattr(task.load_realtime, "end_date"):
                    if task.load_realtime.end_date:
                        end_date = str_to_date(task.load_realtime.end_date)
                feed = convert_to_gtfsrt(TripUpdate.find_by_contributor_period(task.load_realtime.contributors,
                                                                               begin_date,
                                                                               end_date),
                                         gtfs_realtime_pb2.FeedHeader.FULL_DATASET)

                with self._get_producer() as producer:
                    log.info('Publishing full feed...')
                    producer.publish(feed.SerializeToString(), routing_key=task.load_realtime.queue_name)
                    log.info('Full feed published.')
            finally:
                db.session.remove()
Exemplo n.º 3
0
def test_invalid_date():
    res = str_to_date('aaaa')
    assert res == None
Exemplo n.º 4
0
def test_valid_date():
    res = str_to_date('20151210')
    assert res == datetime.date(2015, 12, 10)
Exemplo n.º 5
0
def test_invalid_date():
    res = str_to_date("aaaa")
    assert res == None
Exemplo n.º 6
0
    def build_trip_updates(self, rt_update):
        """
        parse the PIV raw json stored in the rt_update object (in Kirin db)
        and return a list of trip updates

        The TripUpdates are not associated with the RealTimeUpdate at this point
        """
        log_dict = {}
        try:
            json = ujson.loads(rt_update.raw_data)
        except ValueError as e:
            raise InvalidArguments("invalid json: {}".format(str(e)))

        dict_objects = get_value(json, "objects")
        json_train = get_value(
            dict_objects[0],
            "object")  # TODO: can we get more than 1 relevant in objects[]?
        brand_code = json_train.get("marque", {}).get("code")
        if brand_code in ["TN", "TNRER"]:
            raise InvalidArguments(
                '"{}" marque code is not supported'.format(brand_code))
        piv_disruptions = get_value(json_train, "evenement", nullable=True)
        plan_transport_source = get_value(json_train,
                                          "planTransportSource",
                                          nullable=True)

        if not piv_disruptions and not plan_transport_source:
            raise InvalidArguments(
                'No object "evenement" or "planTransportSource" available in feed provided'
            )

        higher_trip_disruption = _get_piv_higher_trip_disruption(
            piv_disruptions, plan_transport_source)

        json_train["evenement"] = higher_trip_disruption
        train_date_str = get_value(json_train, "dateCirculation")
        train_numbers = get_value(json_train, "numero")
        train_company = get_value(get_value(json_train, "operateur"),
                                  "codeOperateur")
        mode_dict = get_value(json_train, "modeTransport")
        train_mode = get_value(mode_dict, "codeMode")
        train_submode = get_value(mode_dict, "codeSousMode")
        train_typemode = get_value(mode_dict, "typeMode")
        piv_key = "{d}:{n}:{c}:{m}:{s}:{t}".format(d=train_date_str,
                                                   n=train_numbers,
                                                   c=train_company,
                                                   m=train_mode,
                                                   s=train_submode,
                                                   t=train_typemode)

        list_ads = get_value(json_train, "listeArretsDesserte")
        ads = _retrieve_interesting_stops(get_value(list_ads, "arret"))
        if len(ads) < 2:
            raise InvalidArguments(
                'invalid json, "listeArretsDesserte/arret" has less than 2 valid stop_times in '
                "json elt {elt}".format(elt=ujson.dumps(json_train)))
        # replace by cleaned and sorted version of stoptimes list.
        json_train["listeArretsDesserte"]["arret"] = ads

        is_trip_addition = higher_trip_disruption.get("type") == "CREATION"
        train_date = str_to_date(train_date_str)
        vj = self._get_navitia_vj(piv_key, train_date, ads, is_trip_addition)

        trip_updates = [self._make_trip_update(json_train, vj)]

        return trip_updates, log_dict
Exemplo n.º 7
0
    def _on_request(self, message):
        log = logging.getLogger(__name__)
        status = "OK"
        log_dict = {}
        start_datetime = datetime.utcnow()
        try:
            task = task_pb2.Task()
            try:
                # `body` is a string, but we need binary type for
                # `ParseFromString()` to work.  It seems to work.
                body = bytes(message.payload, encoding="utf-8")
                task.ParseFromString(body)
            except DecodeError as e:
                log.warning("invalid protobuf: {}".format(str(e)))
                return

            log.info("Getting a full feed publication request",
                     extra={"task": task})
            if task.action != task_pb2.LOAD_REALTIME or not task.load_realtime:
                return
            begin_date = None
            end_date = None
            if hasattr(task.load_realtime,
                       "begin_date") and task.load_realtime.begin_date:
                begin_date = str_to_date(task.load_realtime.begin_date)

            if hasattr(task.load_realtime,
                       "end_date") and task.load_realtime.end_date:
                end_date = str_to_date(task.load_realtime.end_date)
            feed = convert_to_gtfsrt(
                TripUpdate.find_by_contributor_period(
                    task.load_realtime.contributors, begin_date, end_date),
                gtfs_realtime_pb2.FeedHeader.FULL_DATASET,
            )

            feed_str = feed.SerializeToString()
            log_dict.update({
                "contributors": task.load_realtime.contributors,
                "routing_key": task.load_realtime.queue_name,
                "output_trip_update_count": len(feed.entity),
                "output_feed_size": sys.getsizeof(feed_str),
            })
            log.info(
                "Starting of full feed publication {}, {}".format(
                    len(feed_str), task),
                extra={
                    "size": len(feed_str),
                    "task": task
                },
            )
            record_custom_parameter("contributors",
                                    task.load_realtime.contributors)
            # http://docs.celeryproject.org/projects/kombu/en/latest/userguide/producers.html#bypassing-routing-by-using-the-anon-exchange
            self.producer.publish(
                feed_str,
                routing_key=task.load_realtime.queue_name,
                retry=True,
                retry_policy={
                    "interval_start": 0,  # First retry immediately,
                    "interval_step": 2,  # then increase by 2s for every retry.
                    "interval_max":
                    10,  # but don't exceed 10s between retries.
                    "max_retries":
                    self.max_retries,  # give up after 10 (by default) tries.
                },
            )
        except Exception as e:
            status = "failure"
            log_dict.update({"reason": str(e)})
            record_custom_parameter("reason", str(e))
        finally:
            duration = (datetime.utcnow() - start_datetime).total_seconds()
            log_dict.update({"duration": duration})
            record_call("kirin_reload_info", status, **log_dict)
            log.info("End of full feed publication",
                     extra={
                         "duration": duration,
                         "task": task
                     })
            db.session.remove()
        return log_dict