Example #1
0
    def _process_response_time_api(self, response_time, api):
        """
        Analyses the response time of an API.

        This function is always called on the response time of an API in
        order to update the internal state with the average response time.

        Parameters
        ----------
        response_time : float
            Elapsed time in milliseconds.
        api : object
            The API which had the response time passed above.

        """
        logger.info("%s: response time %sms" % (api.name, response_time))
        with self._locks["_api_response_times"]:
            if (len(self._api_response_times[api.name]) >
                    self.MAX_HISTORY_RTIME):
                # Remove from the history once it reaches max limit
                self._api_response_times[api.name].pop(0)
            self._api_response_times[api.name] += [response_time]
            # Sorted returns a new cloned list
            np_array = numpy.array(sorted(self._api_response_times[api.name]))

        # Compute the response time of self.PERCENTILE percentage of requests
        p = numpy.percentile(np_array, self.PERCENTILE)
        with self._locks["_percentile_map"]:
            self._percentile_map[api.name] = p
        logger.debug("%s - %s percentile result: %s" %
                     (api.name, self.PERCENTILE, p))
Example #2
0
    def remove_api(self, api):
        """
        Removes the API from the internal list.

        Parameters
        ----------
        api : object
            The object implementing BaseThirdPartyAPIService class.

        """
        logger.info("Removing API: %s" % api.name)
        self._locks["_api_list"].acquire_write()
        removed_api = self._api_list.pop(api.name, None)
        self._locks["_api_list"].release_write()
        if removed_api is not None:
            logger.debug("Removed API")
        else:
            logger.debug("Tried to remove API which is "
                         "not present in the list")
            return
        with self._locks["_api_response_times"]:
            self._api_response_times.pop(api.name, None)
        with self._locks["_percentile_map"]:
            self._percentile_map.pop(api.name, None)
        logger.info("New list: %s" % self._api_list.keys())
Example #3
0
    def __init__(self, api_list=[], config_filepath='config.ini'):
        """
        Parameters
        ----------
        api_list : list
            List of objects that are implementing the default class
            BaseThirdPartyAPIService.

        """
        apimux_cfg = config.parse_config(config_filepath)
        self.PERCENTILE = apimux_cfg.getint("PERCENTILE")
        self.MAX_HISTORY_RTIME = apimux_cfg.getint("MAX_HISTORY_RTIME")
        self.MAX_WAIT_TIME = apimux_cfg.getint("MAX_WAIT_TIME")
        self._PERIODIC_CHECK_INTERVAL = apimux_cfg.getint("PERIODIC_CHECK")

        logger.debug("Initializing the APIMultiplexer class")
        # Locks used to prevent multi-threading issues
        self._locks = {}
        # ReadWriteLock allows multiple readers and only one writer
        self._locks["_api_list"] = ReadWriteLock()
        self._api_list = {}
        self._locks["_api_response_times"] = Lock()
        self._api_response_times = {}
        self._locks["_percentile_map"] = Lock()
        self._percentile_map = {}
        self._futures_not_finished = {}
        self._locks["_futures_not_finished"] = Lock()

        # Registering all APIs passed as parameters
        if len(api_list) > 0:
            for x in api_list:
                self.register_new_api(x)

        self._ignore_slow_apis = apimux_cfg.getboolean("ignore_slow_apis")
        self._slow_multiplied = apimux_cfg.getfloat("slow_multiplied")
        self._exploration_coefficient = apimux_cfg.getint(
            "exploration_coefficient")

        # Whether it should enable round robing or not
        self._round_robin = apimux_cfg.getboolean("round_robin")
        if self._round_robin:
            logger.info("Round robin enabled!")
            # Disable exploration if round robin is enabled
            self._exploration_coefficient = 0
        elif self._exploration_coefficient > 0:
            logger.info("Exploration with percentage %s enabled!" %
                        self._exploration_coefficient)
        self._current_order = []
        self._locks["_current_order"] = Lock()

        if apimux_cfg.getboolean("enable_periodic_check"):
            # Starting a background thread which will run periodically
            # the 'check' method if implemented by the user for an API
            self._periodic_check_thread = Thread(target=self._periodic_check,
                                                 args=())
            self._periodic_check_thread.setDaemon(True)
            self._periodic_check_thread.start()
Example #4
0
    def register_new_api(self, api):
        """
        Registers new API and adds it to the internal list.

        Parameters
        ----------
        api : object
            The object implementing BaseThirdPartyAPIService class.

        """
        logger.info("New API to register: %s" % api.name)
        self._locks["_api_list"].acquire_write()
        if self._api_list.get(api.name, None) is not None:
            raise Exception("API already exists in the list")
        self._api_list[api.name] = api
        self._locks["_api_list"].release_write()
        # All APIs start from 0 initially, this will be automatically
        # reconfigured based on the performance of the APIs.
        with self._locks["_api_response_times"]:
            self._api_response_times[api.name] = []
        with self._locks["_percentile_map"]:
            self._percentile_map[api.name] = 0
        logger.info("New list: %s" % self._api_list.keys())
Example #5
0
    api_list=[
        GoogleTranslateWithContext(),
        GoogleTranslateWithoutContext(),
        MicrosoftTranslateWithContext(),
        MicrosoftTranslateWithoutContext(),
    ],
    config_filepath=os.environ.get("API_MUX_CONFIG__TRANSLATORS", ""),
)

wordnik_api_keys = []
for env_var_name in os.environ:
    if env_var_name.startswith("WORDNIK_API_KEY"):
        wordnik_api_keys += [env_var_name]
wordnik_translators = [WordnikTranslate(apikey) for apikey in wordnik_api_keys]
a_b_testing_wordnik = len(wordnik_translators) > 1
logger.info("Number of wordnik api keys: %s" % len(wordnik_translators))
api_mux_worddefs = APIMultiplexer(
    api_list=wordnik_translators,
    config_filepath=os.environ.get("API_MUX_CONFIG__EN2EN", ""),
)


def get_all_translations(data):
    if data["from_lang_code"] == data["to_lang_code"] == "en":
        # Wordnik case, get only the top result
        response = get_next_results(data, number_of_results=1)
    else:
        response = get_next_results(data, number_of_results=-1)

    logger.debug(f"Zeeguu-API - Request data: {data}")
    return response
Example #6
0
            return None
        return response


api_mux_translators = APIMultiplexer(api_list=[
    GoogleTranslateWithContext(), GoogleTranslateWithoutContext(),
    MicrosoftTranslateWithContext(), MicrosoftTranslateWithoutContext()],
    config_filepath=os.environ.get("API_MUX_CONFIG__TRANSLATORS", ''))

wordnik_api_keys = []
for env_var_name in os.environ:
    if env_var_name.startswith('WORDNIK_API_KEY'):
        wordnik_api_keys += [env_var_name]
wordnik_translators = [WordnikTranslate(apikey) for apikey in wordnik_api_keys]
a_b_testing_wordnik = len(wordnik_translators) > 1
logger.info("Number of wordnik api keys: %s" % len(wordnik_translators))
api_mux_worddefs = APIMultiplexer(
    api_list=wordnik_translators,
    config_filepath=os.environ.get("API_MUX_CONFIG__EN2EN", ''))


def get_all_translations(data):
    if data["from_lang_code"] == data["to_lang_code"] == "en":
        # Wordnik case, get only the top result
        response = get_next_results(data, number_of_results=1)
    else:
        response = get_next_results(data, number_of_results=-1)

    logger.debug(f"Zeeguu-API - Request data: {data}")
    return response