示例#1
0
    def request(self, pool, tasks, query_params={}, **kwargs):
        """
        Issue a bulk endpoint request with network code granularity. For
        distributed physical networks a request execution is delegated to a
        secondary-level task.
        """
        assert hasattr(self, '_routes'), 'Missing routes.'

        default_task = self._get_task_by_kw(tasks, 'default')
        combining_task = self._get_task_by_kw(tasks, 'combining')

        http_method = kwargs.pop('http_method',
                                 settings.EIDA_FEDERATOR_DEFAULT_HTTP_METHOD)

        retval = []

        for net, routes in self._routes.items():
            # create subcontext
            ctx = Context()
            self._ctx.append(ctx)

            if len(routes) == 1:
                if http_method == 'GET':
                    self.logger.debug('Force HTTP POST endpoint requests.')

                self.logger.debug('Creating {!r} for net={!r} ...'.format(
                    default_task, net))
                # NOTE(damb): For bulk requests there's only http_method='POST'
                t = default_task(BulkFdsnRequestHandler(
                    routes[0].url,
                    stream_epochs=routes[0].streams,
                    query_params=query_params),
                                 context=ctx,
                                 name=net,
                                 http_method='POST',
                                 **kwargs)

            elif len(routes) > 1:
                self.logger.debug('Creating {!r} for net={!r} ...'.format(
                    combining_task, net))
                t = combining_task(routes,
                                   query_params,
                                   name=net,
                                   context=ctx,
                                   http_method=http_method,
                                   **kwargs)
            else:
                raise RoutingError('Missing routes.')

            result = pool.apply_async(t)
            retval.append(result)

        return retval
示例#2
0
    def _handle_413(self, result):
        self.logger.info(
            'Handle endpoint HTTP status code 413 (url={}, '
            'stream_epochs={}).'.format(result.data.url,
                                        result.data.stream_epochs))
        self.logger.debug(
            'Creating SAATask for (url={}, '
            'stream_epochs={}) ...'.format(result.data.url,
                                           result.data.stream_epochs))
        ctx = Context()
        self._ctx.append(ctx)

        t = WFCatalogSplitAndAlignTask(
            result.data.url, result.data.stream_epochs[0],
            query_params=self.query_params,
            endtime=self.DEFAULT_ENDTIME,
            context=ctx,
            keep_tempfiles=self._keep_tempfiles,)

        result = self._pool.apply_async(t)
        self._results.append(result)
示例#3
0
    def request(self, pool, tasks, query_params={}, **kwargs):
        """
        Issue granular endpoint requests.
        """

        assert hasattr(self, '_routes'), 'Missing routes.'

        default_task = self._get_task_by_kw(tasks, 'default')

        retval = []
        for route in self._routes:
            self.logger.debug('Creating {!r} for {!r} ...'.format(
                default_task, route))
            ctx = Context()
            self._ctx.append(ctx)
            t = default_task(GranularFdsnRequestHandler(
                route.url, route.streams[0], query_params=query_params),
                             context=ctx,
                             **kwargs)
            result = pool.apply_async(t)
            retval.append(result)

        return retval
示例#4
0
    def request(self, pool, tasks, query_params={}, **kwargs):
        """
        Issue a bulk endpoint request with network granularity.
        """

        assert hasattr(self, '_routes'), 'Missing routes.'

        default_task = self._get_task_by_kw(tasks, 'default')

        http_method = kwargs.pop('http_method',
                                 settings.EIDA_FEDERATOR_DEFAULT_HTTP_METHOD)
        if http_method == 'GET':
            self.logger.debug('Force HTTP POST endpoint requests.')

        retval = []
        for net, bulk_routes in self._routes.items():
            self.logger.debug('Creating tasks for net={!r} ...'.format(net))

            for bulk_route in bulk_routes:
                self.logger.debug('Creating {!r} for {!r} ...'.format(
                    default_task, bulk_route))

                ctx = Context()
                self._ctx.append(ctx)

                # NOTE(damb): For bulk requests there's only http_method='POST'
                t = default_task(BulkFdsnRequestHandler(
                    bulk_route.url,
                    stream_epochs=bulk_route.streams,
                    query_params=query_params),
                                 context=ctx,
                                 http_method='POST',
                                 **kwargs)
                result = pool.apply_async(t)
                retval.append(result)

        return retval
示例#5
0
    def request(self, pool, tasks, query_params={}, **kwargs):
        """
        Issue combining tasks. Issuing endpoint requests is delegated to those
        tasks.
        """
        assert hasattr(self, '_routes'), 'Missing routes.'

        combining_task = self._get_task_by_kw(tasks, 'combining')

        retval = []
        for net, routes in self._routes.items():
            ctx = Context()
            self._ctx.append(ctx)
            self.logger.debug('Creating {!r} for net={!r} ...'.format(
                combining_task, net))
            t = combining_task(routes,
                               query_params,
                               name=net,
                               context=ctx,
                               **kwargs)
            result = pool.apply_async(t)
            retval.append(result)

        return retval
示例#6
0
 def before_request():
     g.request_start_time = datetime.datetime.utcnow()
     g.request_id = uuid.uuid4()
     g.ctx = Context(ctx=g.request_id)
     g.ctx.acquire()
示例#7
0
    def _run(self):
        """
        Combine `StationXML <http://www.fdsn.org/xml/station/>`_
        :code:`<Network></Network>` information.
        """
        self.logger.info('Executing task {!r} ...'.format(self))
        self._pool = ThreadPool(processes=self._num_workers)

        for route in self._routes:
            self.logger.debug(
                'Creating DownloadTask for route {!r} ...'.format(route))
            ctx = Context()
            self._ctx.append(ctx)

            t = RawDownloadTask(GranularFdsnRequestHandler(
                route.url, route.streams[0], query_params=self.query_params),
                                decode_unicode=True,
                                context=ctx,
                                keep_tempfiles=self._keep_tempfiles,
                                http_method=self._http_method)

            # apply DownloadTask asynchronoulsy to the worker pool
            result = self._pool.apply_async(t)

            self._results.append(result)

        self._pool.close()

        # fetch results ready
        while True:
            ready = []
            for result in self._results:
                if result.ready():
                    _result = result.get()
                    if _result.status_code == 200:
                        if self._level in ('channel', 'response'):
                            # merge <Channel></Channel> elements into
                            # <Station></Station> from the correct
                            # <Network></Network> epoch element
                            for _net_element in self._extract_net_elements(
                                    _result.data):

                                # find the correct <Network></Network> epoch
                                # element
                                net_element, known = self._emerge_net_element(
                                    _net_element,
                                    exclude_tags=[
                                        '{}{}'.format(ns, self.STATION_TAG) for
                                        ns in settings.STATIONXML_NAMESPACES
                                    ])

                                if not known:
                                    continue

                                # append/merge station elements
                                for sta_element in \
                                        self._emerge_sta_elements(
                                            _net_element):
                                    self._merge_sta_element(
                                        net_element, sta_element)

                        elif self._level == 'station':
                            # append <Station></Station> elements to the
                            # corresponding <Network></Network> epoch
                            for _net_element in self._extract_net_elements(
                                    _result.data):

                                net_element, known = self._emerge_net_element(
                                    _net_element,
                                    exclude_tags=[
                                        '{}{}'.format(ns, self.STATION_TAG) for
                                        ns in settings.STATIONXML_NAMESPACES
                                    ])

                                if not known:
                                    continue

                                # append station elements
                                # NOTE(damb): <Station></Station> elements
                                # defined by multiple EIDA nodes are simply
                                # appended; no merging is performed
                                for sta_element in \
                                        self._emerge_sta_elements(
                                            _net_element):
                                    net_element.append(sta_element)

                        elif self._level == 'network':
                            for net_element in self._extract_net_elements(
                                    _result.data):
                                _, _ = self._emerge_net_element(net_element)

                        self._clean(_result)
                        self._sizes.append(_result.length)

                    else:
                        self._handle_error(_result)
                        self._sizes.append(0)

                    ready.append(result)

            for result in ready:
                self._results.remove(result)

            if not self._results:
                break

            if self._has_inactive_ctx():
                self.logger.debug('{}: Closing ...'.format(self.name))
                self._terminate()
                raise self.MissingContextLock

        self._pool.join()

        if not sum(self._sizes):
            self.logger.warning(
                'Task {!r} terminates with no valid result.'.format(self))
            return Result.nocontent(extras={'type_task': self._TYPE})

        _length = 0
        # dump xml tree for <Network></Network> epochs to temporary file
        self.path_tempfile = get_temp_filepath()
        self.logger.debug('{}: tempfile={!r}'.format(self, self.path_tempfile))
        with open(self.path_tempfile, 'wb') as ofd:
            for net_element in self._network_elements:
                s = etree.tostring(net_element)
                _length += len(s)
                ofd.write(s)

        if self._has_inactive_ctx():
            raise self.MissingContextLock

        self.logger.info(
            ('Task {!r} sucessfully finished '
             '(total bytes processed: {}, after processing: {}).').format(
                 self, sum(self._sizes), _length))

        return Result.ok(data=self.path_tempfile,
                         length=_length,
                         extras={'type_task': self._TYPE})
示例#8
0
    def __init__(self, mimetype, query_params={}, stream_epochs=[], **kwargs):
        """
        :param str mimetype: The response's mimetype
        :param dict query_params: Request query parameters
        :param stream_epochs: Stream epochs requested
        :type stream_epochs: List of :py:class:`StreamEpoch`

        :param str logger: Logger name (optional)
        :param request_strategy: Request strategy applied (optional)
        :type request_strategy: :py:class:`RequestStrategyBase`
        :param keep_tempfiles: Flag indicating how to treat temporary files
        :type keep_tempfiles: :py:class:`KeepTempfiles`
        :param str http_method: HTTP method used when issuing requests to
            endpoints
        :param float retry_budget_client: Per client retry-budget in percent.
            The value defines the cut-off error ratio above requests to
            datacenters (DC) are dropped.
        :param proxy_netloc: Proxy netloc delegated to the routing service
            in use
        :type proxy_netloc: str or None
        """

        self.mimetype = mimetype
        self.content_type = (
            '{}; {}'.format(self.mimetype, settings.CHARSET_TEXT)
            if self.mimetype == settings.MIMETYPE_TEXT else self.mimetype)
        self.query_params = query_params
        self.stream_epochs = stream_epochs

        # TODO(damb): Pass as ctor arg.
        self._routing_service = current_app.config['ROUTING_SERVICE']

        self._logger = logging.getLogger(kwargs.get('logger', self.LOGGER))

        self._ctx = kwargs.get('context', Context(uuid.uuid4()))
        if not self._ctx.locked:
            self._ctx.acquire()

        self.logger = ContextLoggerAdapter(self._logger, {'ctx': self._ctx})

        self._keep_tempfiles = kwargs.get('keep_tempfiles', KeepTempfiles.NONE)

        self._retry_budget_client = kwargs.get(
            'retry_budget_client', self.DEFAULT_RETRY_BUDGET_CLIENT)

        self._num_routes = 0
        self._pool = None
        self._results = []
        self._sizes = []

        self._default_endtime = datetime.datetime.utcnow()

        self._nodata = int(self.query_params.get(
            'nodata', settings.FDSN_DEFAULT_NO_CONTENT_ERROR_CODE))

        # lookup resource configuration attributes
        req_strategy = kwargs.get('request_strategy',
                                  self.DEFAULT_REQUEST_STRATEGY)
        if req_strategy not in self.ALLOWED_STRATEGIES:
            raise ConfigurationError(
                'Invalid strategy: {!r}'.format(req_strategy))
        self._strategy = self._STRATEGY_MAP[req_strategy]
        self._strategy = self._strategy(
            context=self._ctx, default_endtime=self.DEFAULT_ENDTIME)

        self._http_method = kwargs.get(
            'request_method', settings.EIDA_FEDERATOR_DEFAULT_HTTP_METHOD)
        self._num_threads = kwargs.get('num_threads', self.POOL_SIZE)
        self._proxy_netloc = kwargs.get('proxy_netloc')

        self._post = True