Skip to content

Commit f01618e

Browse files
committed
updted storage.pluggable class
1 parent 3e27c40 commit f01618e

File tree

3 files changed

+79
-51
lines changed

3 files changed

+79
-51
lines changed

splitio/client/factory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ def _build_pluggable_factory(api_key, cfg):
523523
pluggable_adapter = cfg.get('storageWrapper')
524524
storage_prefix = cfg.get('storagePrefix')
525525
storages = {
526-
'splits': PluggableSplitStorage(pluggable_adapter, storage_prefix),
526+
'splits': PluggableSplitStorage(pluggable_adapter, storage_prefix, cfg['flagSetsFilter'] if cfg['flagSetsFilter'] is not None else []),
527527
'segments': PluggableSegmentStorage(pluggable_adapter, storage_prefix),
528528
'impressions': PluggableImpressionsStorage(pluggable_adapter, sdk_metadata, storage_prefix),
529529
'events': PluggableEventsStorage(pluggable_adapter, sdk_metadata, storage_prefix),

splitio/storage/pluggable.py

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88
from splitio.models.impressions import Impression
99
from splitio.models.telemetry import MethodExceptions, MethodLatencies, TelemetryConfig, MAX_TAGS, get_latency_bucket_index
1010
from splitio.storage import SplitStorage, SegmentStorage, ImpressionStorage, EventStorage, TelemetryStorage
11+
from splitio.util.storage_helper import get_valid_flag_sets, combine_valid_flag_sets
1112

1213
_LOGGER = logging.getLogger(__name__)
1314

1415
class PluggableSplitStorage(SplitStorage):
15-
"""InMemory implementation of a split storage."""
16+
"""InMemory implementation of feature flag storage."""
1617

17-
_SPLIT_NAME_LENGTH = 12
18+
_FEATURE_FLAG_NAME_LENGTH = 19
1819

19-
def __init__(self, pluggable_adapter, prefix=None):
20+
def __init__(self, pluggable_adapter, prefix=None, config_flag_sets=[]):
2021
"""
2122
Class constructor.
2223
@@ -26,51 +27,78 @@ def __init__(self, pluggable_adapter, prefix=None):
2627
:type prefix: str
2728
"""
2829
self._pluggable_adapter = pluggable_adapter
29-
self._prefix = "SPLITIO.split.{split_name}"
30+
self._config_flag_sets = config_flag_sets
31+
self._prefix = "SPLITIO.split.{feature_flag_name}"
3032
self._traffic_type_prefix = "SPLITIO.trafficType.{traffic_type_name}"
31-
self._split_till_prefix = "SPLITIO.splits.till"
33+
self._feature_flag_till_prefix = "SPLITIO.splits.till"
34+
self._feature_flag_set_prefix = 'SPLITIO.set.{flag_set}'
3235
if prefix is not None:
3336
self._prefix = prefix + "." + self._prefix
3437
self._traffic_type_prefix = prefix + "." + self._traffic_type_prefix
35-
self._split_till_prefix = prefix + "." + self._split_till_prefix
38+
self._feature_flag_till_prefix = prefix + "." + self._feature_flag_till_prefix
39+
self._feature_flag_set_prefix = prefix + "." + self._feature_flag_till_prefix
3640

37-
def get(self, split_name):
41+
def get(self, feature_flag_name):
3842
"""
39-
Retrieve a split.
43+
Retrieve a feature flag.
4044
41-
:param split_name: Name of the feature to fetch.
42-
:type split_name: str
45+
:param feature_flag_name: Name of the feature to fetch.
46+
:type feature_flag_name: str
4347
4448
:rtype: splitio.models.splits.Split
4549
"""
4650
try:
47-
split = self._pluggable_adapter.get(self._prefix.format(split_name=split_name))
48-
if not split:
51+
feature_flag = self._pluggable_adapter.get(self._prefix.format(feature_flag_name=feature_flag_name))
52+
if not feature_flag:
4953
return None
50-
return splits.from_raw(split)
54+
return splits.from_raw(feature_flag)
5155
except Exception:
52-
_LOGGER.error('Error getting split from storage')
56+
_LOGGER.error('Error getting feature flag from storage')
5357
_LOGGER.debug('Error: ', exc_info=True)
5458
return None
5559

56-
def fetch_many(self, split_names):
60+
def fetch_many(self, feature_flag_names):
5761
"""
58-
Retrieve splits.
62+
Retrieve feature flags.
5963
60-
:param split_names: Names of the features to fetch.
61-
:type split_name: list(str)
64+
:param feature_flag_names: Names of the features to fetch.
65+
:type feature_flag_name: list(str)
6266
6367
:return: A dict with split objects parsed from queue.
6468
:rtype: dict(split_name, splitio.models.splits.Split)
6569
"""
6670
try:
67-
prefix_added = [self._prefix.format(split_name=split_name) for split_name in split_names]
68-
return {split['name']: splits.from_raw(split) for split in self._pluggable_adapter.get_many(prefix_added)}
71+
prefix_added = [self._prefix.format(feature_flag_name=feature_flag_name) for feature_flag_name in feature_flag_names]
72+
return {feature_flag['name']: splits.from_raw(feature_flag) for feature_flag in self._pluggable_adapter.get_many(prefix_added)}
6973
except Exception:
70-
_LOGGER.error('Error getting split from storage')
74+
_LOGGER.error('Error getting feature flag from storage')
7175
_LOGGER.debug('Error: ', exc_info=True)
7276
return None
7377

78+
def get_feature_flags_by_sets(self, flag_sets):
79+
"""
80+
Retrieve feature flags by flag set.
81+
82+
:param flag_set: Names of the flag set to fetch.
83+
:type flag_set: str
84+
85+
:return: Feature flag names that are tagged with the flag set
86+
:rtype: listt(str)
87+
"""
88+
try:
89+
sets_to_fetch = get_valid_flag_sets(flag_sets, self._config_flag_sets)
90+
if sets_to_fetch == []:
91+
return []
92+
93+
keys = [self._prefix(feature_flag_name) for feature_flag_name in sets_to_fetch]
94+
result_sets = self._pluggable_adapter.get_many(keys)
95+
return list(combine_valid_flag_sets(result_sets))
96+
except Exception:
97+
_LOGGER.error('Error fetching feature flag from storage')
98+
_LOGGER.debug('Error: ', exc_info=True)
99+
return None
100+
101+
74102
# TODO: To be added when producer mode is supported
75103
# def put_many(self, splits, change_number):
76104
# """
@@ -127,14 +155,14 @@ def update(self, to_add, to_delete, new_change_number):
127155

128156
def get_change_number(self):
129157
"""
130-
Retrieve latest split change number.
158+
Retrieve latest feature flag change number.
131159
132160
:rtype: int
133161
"""
134162
try:
135-
return self._pluggable_adapter.get(self._split_till_prefix)
163+
return self._pluggable_adapter.get(self._feature_flag_till_prefix)
136164
except Exception:
137-
_LOGGER.error('Error getting change number in split storage')
165+
_LOGGER.error('Error getting change number in feature flag storage')
138166
_LOGGER.debug('Error: ', exc_info=True)
139167
return None
140168

@@ -156,35 +184,35 @@ def get_change_number(self):
156184

157185
def get_split_names(self):
158186
"""
159-
Retrieve a list of all split names.
187+
Retrieve a list of all feature flag names.
160188
161-
:return: List of split names.
189+
:return: List of feature flag names.
162190
:rtype: list(str)
163191
"""
164192
try:
165-
return [split.name for split in self.get_all()]
193+
return [feature_flag.name for feature_flag in self.get_all()]
166194
except Exception:
167-
_LOGGER.error('Error getting split names from storage')
195+
_LOGGER.error('Error getting feature flag names from storage')
168196
_LOGGER.debug('Error: ', exc_info=True)
169197
return None
170198

171199
def get_all(self):
172200
"""
173-
Return all the splits.
201+
Return all the feature flags.
174202
175-
:return: List of all the splits.
203+
:return: List of all the feature flags.
176204
:rtype: list
177205
"""
178206
try:
179-
return [splits.from_raw(self._pluggable_adapter.get(key)) for key in self._pluggable_adapter.get_keys_by_prefix(self._prefix[:-self._SPLIT_NAME_LENGTH])]
207+
return [splits.from_raw(self._pluggable_adapter.get(key)) for key in self._pluggable_adapter.get_keys_by_prefix(self._prefix[:-self._FEATURE_FLAG_NAME_LENGTH])]
180208
except Exception:
181-
_LOGGER.error('Error getting split keys from storage')
209+
_LOGGER.error('Error getting feature flag keys from storage')
182210
_LOGGER.debug('Error: ', exc_info=True)
183211
return None
184212

185213
def traffic_type_exists(self, traffic_type_name):
186214
"""
187-
Return whether the traffic type exists in at least one split in cache.
215+
Return whether the traffic type exists in at least one feature flag in cache.
188216
189217
:param traffic_type_name: Traffic type to validate.
190218
:type traffic_type_name: str
@@ -195,7 +223,7 @@ def traffic_type_exists(self, traffic_type_name):
195223
try:
196224
return self._pluggable_adapter.get(self._traffic_type_prefix.format(traffic_type_name=traffic_type_name)) != None
197225
except Exception:
198-
_LOGGER.error('Error getting split info from storage')
226+
_LOGGER.error('Error getting traffic type info from storage')
199227
_LOGGER.debug('Error: ', exc_info=True)
200228
return None
201229

@@ -264,21 +292,21 @@ def kill_locally(self, split_name, default_treatment, change_number):
264292

265293
def get_all_splits(self):
266294
"""
267-
Return all the splits.
295+
Return all the feature flags.
268296
269-
:return: List of all the splits.
297+
:return: List of all the feature flags.
270298
:rtype: list
271299
"""
272300
try:
273301
return self.get_all()
274302
except Exception:
275-
_LOGGER.error('Error fetching splits from storage')
303+
_LOGGER.error('Error fetching feature flags from storage')
276304
_LOGGER.debug('Error: ', exc_info=True)
277305
return None
278306

279307
def is_valid_traffic_type(self, traffic_type_name):
280308
"""
281-
Return whether the traffic type exists in at least one split in cache.
309+
Return whether the traffic type exists in at least one feature flag in cache.
282310
283311
:param traffic_type_name: Traffic type to validate.
284312
:type traffic_type_name: str
@@ -289,7 +317,7 @@ def is_valid_traffic_type(self, traffic_type_name):
289317
try:
290318
return self.traffic_type_exists(traffic_type_name)
291319
except Exception:
292-
_LOGGER.error('Error getting split info from storage')
320+
_LOGGER.error('Error getting traffic type info from storage')
293321
_LOGGER.debug('Error: ', exc_info=True)
294322
return None
295323

tests/storage/test_pluggable.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ def test_init(self):
138138
prefix = 'myprefix.'
139139
else:
140140
prefix = ''
141-
assert(pluggable_split_storage._prefix == prefix + "SPLITIO.split.{split_name}")
141+
assert(pluggable_split_storage._prefix == prefix + "SPLITIO.split.{feature_flag_name}")
142142
assert(pluggable_split_storage._traffic_type_prefix == prefix + "SPLITIO.trafficType.{traffic_type_name}")
143-
assert(pluggable_split_storage._split_till_prefix == prefix + "SPLITIO.splits.till")
143+
assert(pluggable_split_storage._feature_flag_till_prefix == prefix + "SPLITIO.splits.till")
144144

145145
# TODO: To be added when producer mode is aupported
146146
# def test_put_many(self):
@@ -163,10 +163,10 @@ def test_get(self):
163163
pluggable_split_storage = PluggableSplitStorage(self.mock_adapter, prefix=sprefix)
164164

165165
split1 = splits.from_raw(splits_json['splitChange1_2']['splits'][0])
166-
split_name = splits_json['splitChange1_2']['splits'][0]['name']
166+
feature_flag_name = splits_json['splitChange1_2']['splits'][0]['name']
167167

168-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split_name), split1.to_json())
169-
assert(pluggable_split_storage.get(split_name).to_json() == splits.from_raw(splits_json['splitChange1_2']['splits'][0]).to_json())
168+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=feature_flag_name), split1.to_json())
169+
assert(pluggable_split_storage.get(feature_flag_name).to_json() == splits.from_raw(splits_json['splitChange1_2']['splits'][0]).to_json())
170170
assert(pluggable_split_storage.get('not_existing') == None)
171171

172172
def test_fetch_many(self):
@@ -178,8 +178,8 @@ def test_fetch_many(self):
178178
split2_temp['name'] = 'another_split'
179179
split2 = splits.from_raw(split2_temp)
180180

181-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split1.name), split1.to_json())
182-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split2.name), split2.to_json())
181+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split1.name), split1.to_json())
182+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split2.name), split2.to_json())
183183
fetched = pluggable_split_storage.fetch_many([split1.name, split2.name])
184184
assert(fetched[split1.name].to_json() == split1.to_json())
185185
assert(fetched[split2.name].to_json() == split2.to_json())
@@ -217,8 +217,8 @@ def test_get_split_names(self):
217217
split2_temp = splits_json['splitChange1_2']['splits'][0].copy()
218218
split2_temp['name'] = 'another_split'
219219
split2 = splits.from_raw(split2_temp)
220-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split1.name), split1.to_json())
221-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split2.name), split2.to_json())
220+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split1.name), split1.to_json())
221+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split2.name), split2.to_json())
222222
assert(pluggable_split_storage.get_split_names() == [split1.name, split2.name])
223223

224224
def test_get_all(self):
@@ -230,8 +230,8 @@ def test_get_all(self):
230230
split2_temp['name'] = 'another_split'
231231
split2 = splits.from_raw(split2_temp)
232232

233-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split1.name), split1.to_json())
234-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split2.name), split2.to_json())
233+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split1.name), split1.to_json())
234+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split2.name), split2.to_json())
235235
all_splits = pluggable_split_storage.get_all()
236236
assert([all_splits[0].to_json(), all_splits[1].to_json()] == [split1.to_json(), split2.to_json()])
237237

0 commit comments

Comments
 (0)