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
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
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)
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