Ejemplo n.º 1
0
    def get_treatment_with_config(self, key, feature, attributes=None):
        """
        Get the treatment and config for a feature and key, with optional dictionary of attributes.

        This method never raises an exception. If there's a problem, the appropriate log message
        will be generated and the method will return the CONTROL treatment.

        :param key: The key for which to get the treatment
        :type key: str
        :param feature: The name of the feature for which to get the treatment
        :type feature: str
        :param attributes: An optional dictionary of attributes
        :type attributes: dict
        :return: The treatment for the key and feature
        :rtype: tuple(str, str)
        """
        try:
            if self.destroyed:
                self._logger.error(
                    "Client has already been destroyed - no calls possible")
                return CONTROL, None

            start = int(round(time.time() * 1000))

            matching_key, bucketing_key = input_validator.validate_key(key)
            feature = input_validator.validate_feature_name(feature)

            if (matching_key is None and bucketing_key is None) \
                    or feature is None \
                    or not input_validator.validate_attributes(attributes):
                return CONTROL, None

            result = self._evaluator.evaluate_treatment(
                feature, matching_key, bucketing_key, attributes)

            impression = self._build_impression(
                matching_key, feature, result['treatment'],
                result['impression']['label'],
                result['impression']['change_number'], bucketing_key, start)

            self._record_stats(impression, start, self._METRIC_GET_TREATMENT)
            self._send_impression_to_listener(impression, attributes)
            return result['treatment'], result['configurations']
        except Exception:  #pylint: disable=broad-except
            self._logger.error('Error getting treatment for feature')
            self._logger.debug('Error: ', exc_info=True)
            try:
                impression = self._build_impression(
                    matching_key, feature, CONTROL, Label.EXCEPTION,
                    self._split_storage.get_change_number(), bucketing_key,
                    start)
                self._record_stats(impression, start,
                                   self._METRIC_GET_TREATMENT)
                self._send_impression_to_listener(impression, attributes)
            except Exception:  # pylint: disable=broad-except
                self._logger.error(
                    'Error reporting impression into get_treatment exception block'
                )
                self._logger.debug('Error: ', exc_info=True)
            return CONTROL, None
Ejemplo n.º 2
0
    def _make_evaluation(self, key, feature, attributes, method_name,
                         metric_name):
        try:
            if self.destroyed:
                self._logger.error(
                    "Client has already been destroyed - no calls possible")
                return CONTROL, None

            start = int(round(time.time() * 1000))

            matching_key, bucketing_key = input_validator.validate_key(
                key, method_name)
            feature = input_validator.validate_feature_name(
                feature,
                self.ready,
                self._factory._get_storage('splits'),  # pylint: disable=protected-access
                method_name)

            if (matching_key is None and bucketing_key is None) \
                    or feature is None \
                    or not input_validator.validate_attributes(attributes, method_name):
                return CONTROL, None

            result = self._evaluate_if_ready(matching_key, bucketing_key,
                                             feature, attributes)

            impression = self._build_impression(
                matching_key, feature, result['treatment'],
                result['impression']['label'],
                result['impression']['change_number'], bucketing_key, start)

            self._record_stats([impression], start, metric_name)
            self._send_impression_to_listener(impression, attributes)
            return result['treatment'], result['configurations']
        except Exception:  # pylint: disable=broad-except
            self._logger.error('Error getting treatment for feature')
            self._logger.debug('Error: ', exc_info=True)
            try:
                impression = self._build_impression(
                    matching_key, feature, CONTROL, Label.EXCEPTION,
                    self._split_storage.get_change_number(), bucketing_key,
                    start)
                self._record_stats([impression], start, metric_name)
                self._send_impression_to_listener(impression, attributes)
            except Exception:  # pylint: disable=broad-except
                self._logger.error(
                    'Error reporting impression into get_treatment exception block'
                )
                self._logger.debug('Error: ', exc_info=True)
            return CONTROL, None
Ejemplo n.º 3
0
    def _make_evaluations(self, key, features, attributes, method_name,
                          metric_name):
        if self.destroyed:
            _LOGGER.error(
                "Client has already been destroyed - no calls possible")
            return input_validator.generate_control_treatments(
                features, method_name)
        if self._factory._waiting_fork():
            _LOGGER.error("Client is not ready - no calls possible")
            return input_validator.generate_control_treatments(
                features, method_name)

        start = int(round(time.time() * 1000))

        matching_key, bucketing_key = input_validator.validate_key(
            key, method_name)
        if matching_key is None and bucketing_key is None:
            return input_validator.generate_control_treatments(
                features, method_name)

        if input_validator.validate_attributes(attributes,
                                               method_name) is False:
            return input_validator.generate_control_treatments(
                features, method_name)

        features, missing = input_validator.validate_features_get_treatments(
            method_name,
            features,
            self.ready,
            self._factory._get_storage('splits')  # pylint: disable=protected-access
        )
        if features is None:
            return {}

        bulk_impressions = []
        treatments = {name: (CONTROL, None) for name in missing}

        try:
            evaluations = self._evaluate_features_if_ready(
                matching_key, bucketing_key, list(features), attributes)

            for feature in features:
                try:
                    result = evaluations[feature]
                    impression = self._build_impression(
                        matching_key, feature, result['treatment'],
                        result['impression']['label'],
                        result['impression']['change_number'], bucketing_key,
                        utctime_ms())

                    bulk_impressions.append(impression)
                    treatments[feature] = (result['treatment'],
                                           result['configurations'])

                except Exception:  # pylint: disable=broad-except
                    _LOGGER.error('%s: An exception occured when evaluating '
                                  'feature %s returning CONTROL.' %
                                  (method_name, feature))
                    treatments[feature] = CONTROL, None
                    _LOGGER.debug('Error: ', exc_info=True)
                    continue

            # Register impressions
            try:
                if bulk_impressions:
                    self._record_stats([(i, attributes)
                                        for i in bulk_impressions], start,
                                       metric_name)
            except Exception:  # pylint: disable=broad-except
                _LOGGER.error('%s: An exception when trying to store '
                              'impressions.' % method_name)
                _LOGGER.debug('Error: ', exc_info=True)

            return treatments
        except Exception:  # pylint: disable=broad-except
            _LOGGER.error('Error getting treatment for features')
            _LOGGER.debug('Error: ', exc_info=True)
        return input_validator.generate_control_treatments(
            list(features), method_name)
Ejemplo n.º 4
0
    def get_treatments_with_config(self, key, features, attributes=None):
        """
        Evaluate multiple features and return a dict with feature -> (treatment, config).

        Get the treatments for a list of features considering a key, with an optional dictionary of
        attributes. This method never raises an exception. If there's a problem, the appropriate
        log message will be generated and the method will return the CONTROL treatment.
        :param key: The key for which to get the treatment
        :type key: str
        :param features: Array of the names of the features for which to get the treatment
        :type feature: list
        :param attributes: An optional dictionary of attributes
        :type attributes: dict
        :return: Dictionary with the result of all the features provided
        :rtype: dict
        """
        if self.destroyed:
            self._logger.error(
                "Client has already been destroyed - no calls possible")
            return input_validator.generate_control_treatments(features)

        start = int(round(time.time() * 1000))

        matching_key, bucketing_key = input_validator.validate_key(key)
        if matching_key is None and bucketing_key is None:
            return input_validator.generate_control_treatments(features)

        if input_validator.validate_attributes(attributes) is False:
            return input_validator.generate_control_treatments(features)

        features = input_validator.validate_features_get_treatments(features)
        if features is None:
            return {}

        bulk_impressions = []
        treatments = {}

        for feature in features:
            try:
                treatment = self._evaluator.evaluate_treatment(
                    feature, matching_key, bucketing_key, attributes)

                impression = self._build_impression(
                    matching_key, feature, treatment['treatment'],
                    treatment['impression']['label'],
                    treatment['impression']['change_number'], bucketing_key,
                    start)

                bulk_impressions.append(impression)
                treatments[feature] = (treatment['treatment'],
                                       treatment['configurations'])

            except Exception:  #pylint: disable=broad-except
                self._logger.error(
                    'get_treatments: An exception occured when evaluating '
                    'feature ' + feature + ' returning CONTROL.')
                treatments[feature] = CONTROL, None
                self._logger.debug('Error: ', exc_info=True)
                continue

        # Register impressions
        try:
            if bulk_impressions:
                self._record_stats(bulk_impressions, start,
                                   self._METRIC_GET_TREATMENTS)
                for impression in bulk_impressions:
                    self._send_impression_to_listener(impression, attributes)
        except Exception:  #pylint: disable=broad-except
            self._logger.error(
                'get_treatments: An exception when trying to store '
                'impressions.')
            self._logger.debug('Error: ', exc_info=True)

        return treatments