Skip to content

Commit 02484d9

Browse files
authored
Merge pull request #597 from splitio/fallback-calculator
Added fallback calculator
2 parents 48e2aa9 + 48c3084 commit 02484d9

File tree

15 files changed

+256
-211
lines changed

15 files changed

+256
-211
lines changed

splitio/client/client.py

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from splitio.models.events import Event, EventWrapper
1111
from splitio.models.telemetry import get_latency_bucket_index, MethodExceptionsAndLatencies
1212
from splitio.client import input_validator
13-
from splitio.client.util import get_fallback_treatment_and_label
1413
from splitio.util.time import get_current_epoch_time_ms, utctime_ms
1514

1615

@@ -41,7 +40,7 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
4140
'impressions_disabled': False
4241
}
4342

44-
def __init__(self, factory, recorder, labels_enabled=True, fallback_treatments_configuration=None):
43+
def __init__(self, factory, recorder, labels_enabled=True, fallback_treatment_calculator=None):
4544
"""
4645
Construct a Client instance.
4746
@@ -63,10 +62,10 @@ def __init__(self, factory, recorder, labels_enabled=True, fallback_treatments_c
6362
self._feature_flag_storage = factory._get_storage('splits') # pylint: disable=protected-access
6463
self._segment_storage = factory._get_storage('segments') # pylint: disable=protected-access
6564
self._events_storage = factory._get_storage('events') # pylint: disable=protected-access
66-
self._evaluator = Evaluator(self._splitter, fallback_treatments_configuration)
65+
self._evaluator = Evaluator(self._splitter, fallback_treatment_calculator)
6766
self._telemetry_evaluation_producer = self._factory._telemetry_evaluation_producer
6867
self._telemetry_init_producer = self._factory._telemetry_init_producer
69-
self._fallback_treatments_configuration = fallback_treatments_configuration
68+
self._fallback_treatment_calculator = fallback_treatment_calculator
7069

7170
@property
7271
def ready(self):
@@ -206,17 +205,17 @@ def _validate_track(self, key, traffic_type, event_type, value=None, properties=
206205
def _get_properties(self, evaluation_options):
207206
return evaluation_options.properties if evaluation_options != None else None
208207

209-
def _get_fallback_treatment_with_config(self, treatment, feature):
210-
label = ""
211-
212-
label, treatment, config = get_fallback_treatment_and_label(self._fallback_treatments_configuration,
213-
feature, treatment, label, _LOGGER)
214-
return treatment, config
208+
def _get_fallback_treatment_with_config(self, feature):
209+
fallback_treatment = self._fallback_treatment_calculator.resolve(feature, "")
210+
return fallback_treatment.treatment, fallback_treatment.config
215211

216212
def _get_fallback_eval_results(self, eval_result, feature):
217213
result = copy.deepcopy(eval_result)
218-
result["impression"]["label"], result["treatment"], result["configurations"] = get_fallback_treatment_and_label(self._fallback_treatments_configuration,
219-
feature, result["treatment"], result["impression"]["label"], _LOGGER)
214+
fallback_treatment = self._fallback_treatment_calculator.resolve(feature, result["impression"]["label"])
215+
result["impression"]["label"] = fallback_treatment.label
216+
result["treatment"] = fallback_treatment.treatment
217+
result["configurations"] = fallback_treatment.config
218+
220219
return result
221220

222221
def _check_impression_label(self, result):
@@ -225,7 +224,7 @@ def _check_impression_label(self, result):
225224
class Client(ClientBase): # pylint: disable=too-many-instance-attributes
226225
"""Entry point for the split sdk."""
227226

228-
def __init__(self, factory, recorder, labels_enabled=True, fallback_treatments_configuration=None):
227+
def __init__(self, factory, recorder, labels_enabled=True, fallback_treatment_calculator=None):
229228
"""
230229
Construct a Client instance.
231230
@@ -240,7 +239,7 @@ def __init__(self, factory, recorder, labels_enabled=True, fallback_treatments_c
240239
241240
:rtype: Client
242241
"""
243-
ClientBase.__init__(self, factory, recorder, labels_enabled, fallback_treatments_configuration)
242+
ClientBase.__init__(self, factory, recorder, labels_enabled, fallback_treatment_calculator)
244243
self._context_factory = EvaluationDataFactory(factory._get_storage('splits'), factory._get_storage('segments'), factory._get_storage('rule_based_segments'))
245244

246245
def destroy(self):
@@ -275,7 +274,7 @@ def get_treatment(self, key, feature_flag_name, attributes=None, evaluation_opti
275274

276275
except:
277276
_LOGGER.error('get_treatment failed')
278-
treatment, _ = self._get_fallback_treatment_with_config(CONTROL, feature_flag_name)
277+
treatment, _ = self._get_fallback_treatment_with_config(feature_flag_name)
279278
return treatment
280279

281280
def get_treatment_with_config(self, key, feature_flag_name, attributes=None, evaluation_options=None):
@@ -301,7 +300,7 @@ def get_treatment_with_config(self, key, feature_flag_name, attributes=None, eva
301300

302301
except Exception:
303302
_LOGGER.error('get_treatment_with_config failed')
304-
return self._get_fallback_treatment_with_config(CONTROL, feature_flag_name)
303+
return self._get_fallback_treatment_with_config(feature_flag_name)
305304

306305
def _get_treatment(self, method, key, feature, attributes=None, evaluation_options=None):
307306
"""
@@ -321,7 +320,7 @@ def _get_treatment(self, method, key, feature, attributes=None, evaluation_optio
321320
:rtype: dict
322321
"""
323322
if not self._client_is_usable(): # not destroyed & not waiting for a fork
324-
return self._get_fallback_treatment_with_config(CONTROL, feature)
323+
return self._get_fallback_treatment_with_config(feature)
325324

326325
start = get_current_epoch_time_ms()
327326
if not self.ready:
@@ -331,7 +330,7 @@ def _get_treatment(self, method, key, feature, attributes=None, evaluation_optio
331330
try:
332331
key, bucketing, feature, attributes, evaluation_options = self._validate_treatment_input(key, feature, attributes, method, evaluation_options)
333332
except _InvalidInputError:
334-
return self._get_fallback_treatment_with_config(CONTROL, feature)
333+
return self._get_fallback_treatment_with_config(feature)
335334

336335
result = self._get_fallback_eval_results(self._NON_READY_EVAL_RESULT, feature)
337336

@@ -376,7 +375,7 @@ def get_treatments(self, key, feature_flag_names, attributes=None, evaluation_op
376375
return {feature_flag: result[0] for (feature_flag, result) in with_config.items()}
377376

378377
except Exception:
379-
return {feature: self._get_fallback_treatment_with_config(CONTROL, feature)[0] for feature in feature_flag_names}
378+
return {feature: self._get_fallback_treatment_with_config(feature)[0] for feature in feature_flag_names}
380379

381380
def get_treatments_with_config(self, key, feature_flag_names, attributes=None, evaluation_options=None):
382381
"""
@@ -400,7 +399,7 @@ def get_treatments_with_config(self, key, feature_flag_names, attributes=None, e
400399
return self._get_treatments(key, feature_flag_names, MethodExceptionsAndLatencies.TREATMENTS_WITH_CONFIG, attributes, evaluation_options)
401400

402401
except Exception:
403-
return {feature: (self._get_fallback_treatment_with_config(CONTROL, feature)) for feature in feature_flag_names}
402+
return {feature: (self._get_fallback_treatment_with_config(feature)) for feature in feature_flag_names}
404403

405404
def get_treatments_by_flag_set(self, key, flag_set, attributes=None, evaluation_options=None):
406405
"""
@@ -624,7 +623,7 @@ def _get_treatments(self, key, features, method, attributes=None, evaluation_opt
624623
"""
625624
start = get_current_epoch_time_ms()
626625
if not self._client_is_usable():
627-
return input_validator.generate_control_treatments(features, self._fallback_treatments_configuration)
626+
return input_validator.generate_control_treatments(features, self._fallback_treatment_calculator)
628627

629628
if not self.ready:
630629
_LOGGER.error("Client is not ready - no calls possible")
@@ -633,7 +632,7 @@ def _get_treatments(self, key, features, method, attributes=None, evaluation_opt
633632
try:
634633
key, bucketing, features, attributes, evaluation_options = self._validate_treatments_input(key, features, attributes, method, evaluation_options)
635634
except _InvalidInputError:
636-
return input_validator.generate_control_treatments(features, self._fallback_treatments_configuration)
635+
return input_validator.generate_control_treatments(features, self._fallback_treatment_calculator)
637636

638637
results = {n: self._get_fallback_eval_results(self._NON_READY_EVAL_RESULT, n) for n in features}
639638
if self.ready:
@@ -726,7 +725,7 @@ def track(self, key, traffic_type, event_type, value=None, properties=None):
726725
class ClientAsync(ClientBase): # pylint: disable=too-many-instance-attributes
727726
"""Entry point for the split sdk."""
728727

729-
def __init__(self, factory, recorder, labels_enabled=True, fallback_treatments_configuration=None):
728+
def __init__(self, factory, recorder, labels_enabled=True, fallback_treatment_calculator=None):
730729
"""
731730
Construct a Client instance.
732731
@@ -741,7 +740,7 @@ def __init__(self, factory, recorder, labels_enabled=True, fallback_treatments_c
741740
742741
:rtype: Client
743742
"""
744-
ClientBase.__init__(self, factory, recorder, labels_enabled, fallback_treatments_configuration)
743+
ClientBase.__init__(self, factory, recorder, labels_enabled, fallback_treatment_calculator)
745744
self._context_factory = AsyncEvaluationDataFactory(factory._get_storage('splits'), factory._get_storage('segments'), factory._get_storage('rule_based_segments'))
746745

747746
async def destroy(self):
@@ -776,7 +775,7 @@ async def get_treatment(self, key, feature_flag_name, attributes=None, evaluatio
776775

777776
except:
778777
_LOGGER.error('get_treatment failed')
779-
treatment, _ = self._get_fallback_treatment_with_config(CONTROL, feature_flag_name)
778+
treatment, _ = self._get_fallback_treatment_with_config(feature_flag_name)
780779
return treatment
781780

782781
async def get_treatment_with_config(self, key, feature_flag_name, attributes=None, evaluation_options=None):
@@ -802,7 +801,7 @@ async def get_treatment_with_config(self, key, feature_flag_name, attributes=Non
802801

803802
except Exception:
804803
_LOGGER.error('get_treatment_with_config failed')
805-
return self._get_fallback_treatment_with_config(CONTROL, feature_flag_name)
804+
return self._get_fallback_treatment_with_config(feature_flag_name)
806805

807806
async def _get_treatment(self, method, key, feature, attributes=None, evaluation_options=None):
808807
"""
@@ -822,7 +821,7 @@ async def _get_treatment(self, method, key, feature, attributes=None, evaluation
822821
:rtype: dict
823822
"""
824823
if not self._client_is_usable(): # not destroyed & not waiting for a fork
825-
return self._get_fallback_treatment_with_config(CONTROL, feature)
824+
return self._get_fallback_treatment_with_config(feature)
826825

827826
start = get_current_epoch_time_ms()
828827
if not self.ready:
@@ -832,7 +831,7 @@ async def _get_treatment(self, method, key, feature, attributes=None, evaluation
832831
try:
833832
key, bucketing, feature, attributes, evaluation_options = self._validate_treatment_input(key, feature, attributes, method, evaluation_options)
834833
except _InvalidInputError:
835-
return self._get_fallback_treatment_with_config(CONTROL, feature)
834+
return self._get_fallback_treatment_with_config(feature)
836835

837836
result = self._get_fallback_eval_results(self._NON_READY_EVAL_RESULT, feature)
838837
if self.ready:
@@ -875,7 +874,7 @@ async def get_treatments(self, key, feature_flag_names, attributes=None, evaluat
875874
return {feature_flag: result[0] for (feature_flag, result) in with_config.items()}
876875

877876
except Exception:
878-
return {feature: self._get_fallback_treatment_with_config(CONTROL, feature)[0] for feature in feature_flag_names}
877+
return {feature: self._get_fallback_treatment_with_config(feature)[0] for feature in feature_flag_names}
879878

880879
async def get_treatments_with_config(self, key, feature_flag_names, attributes=None, evaluation_options=None):
881880
"""
@@ -899,7 +898,7 @@ async def get_treatments_with_config(self, key, feature_flag_names, attributes=N
899898
return await self._get_treatments(key, feature_flag_names, MethodExceptionsAndLatencies.TREATMENTS_WITH_CONFIG, attributes, evaluation_options)
900899

901900
except Exception:
902-
return {feature: (self._get_fallback_treatment_with_config(CONTROL, feature)) for feature in feature_flag_names}
901+
return {feature: (self._get_fallback_treatment_with_config(feature)) for feature in feature_flag_names}
903902

904903
async def get_treatments_by_flag_set(self, key, flag_set, attributes=None, evaluation_options=None):
905904
"""
@@ -1037,7 +1036,7 @@ async def _get_treatments(self, key, features, method, attributes=None, evaluati
10371036
"""
10381037
start = get_current_epoch_time_ms()
10391038
if not self._client_is_usable():
1040-
return input_validator.generate_control_treatments(features, self._fallback_treatments_configuration)
1039+
return input_validator.generate_control_treatments(features, self._fallback_treatment_calculator)
10411040

10421041
if not self.ready:
10431042
_LOGGER.error("Client is not ready - no calls possible")
@@ -1046,7 +1045,7 @@ async def _get_treatments(self, key, features, method, attributes=None, evaluati
10461045
try:
10471046
key, bucketing, features, attributes, evaluation_options = self._validate_treatments_input(key, features, attributes, method, evaluation_options)
10481047
except _InvalidInputError:
1049-
return input_validator.generate_control_treatments(features, self._fallback_treatments_configuration)
1048+
return input_validator.generate_control_treatments(features, self._fallback_treatment_calculator)
10501049

10511050
results = {n: self._get_fallback_eval_results(self._NON_READY_EVAL_RESULT, n) for n in features}
10521051
if self.ready:

0 commit comments

Comments
 (0)