Skip to content

Commit 7cd34eb

Browse files
committed
updated redis, pluggable and localjson storages
1 parent 3396b5f commit 7cd34eb

File tree

4 files changed

+549
-38
lines changed

4 files changed

+549
-38
lines changed

splitio/storage/inmemmory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ def remove_flag_set(self, flag_sets, feature_flag_name, should_filter):
109109

110110
class InMemoryRuleBasedSegmentStorage(RuleBasedSegmentsStorage):
111111
"""InMemory implementation of a feature flag storage base."""
112+
112113
def __init__(self):
113114
"""Constructor."""
114115
self._lock = threading.RLock()
@@ -192,7 +193,7 @@ def _set_change_number(self, new_change_number):
192193

193194
def get_segment_names(self):
194195
"""
195-
Retrieve a list of all excluded segments names.
196+
Retrieve a list of all rule based segments names.
196197
197198
:return: List of segment names.
198199
:rtype: list(str)

splitio/storage/pluggable.py

Lines changed: 241 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,253 @@
55
import threading
66

77
from splitio.optional.loaders import asyncio
8-
from splitio.models import splits, segments
8+
from splitio.models import splits, segments, rule_based_segments
99
from splitio.models.impressions import Impression
1010
from splitio.models.telemetry import MethodExceptions, MethodLatencies, TelemetryConfig, MAX_TAGS,\
1111
MethodLatenciesAsync, MethodExceptionsAsync, TelemetryConfigAsync
12-
from splitio.storage import FlagSetsFilter, SplitStorage, SegmentStorage, ImpressionStorage, EventStorage, TelemetryStorage
12+
from splitio.storage import FlagSetsFilter, SplitStorage, SegmentStorage, ImpressionStorage, EventStorage, TelemetryStorage, RuleBasedSegmentsStorage
1313
from splitio.util.storage_helper import get_valid_flag_sets, combine_valid_flag_sets
1414

1515
_LOGGER = logging.getLogger(__name__)
1616

17+
class PluggableRuleBasedSegmentsStorageBase(RuleBasedSegmentsStorage):
18+
"""RedPluggable storage for rule based segments."""
19+
20+
_RB_SEGMENT_NAME_LENGTH = 23
21+
_TILL_LENGTH = 4
22+
23+
def __init__(self, pluggable_adapter, prefix=None):
24+
"""
25+
Class constructor.
26+
27+
:param redis_client: Redis client or compliant interface.
28+
:type redis_client: splitio.storage.adapters.redis.RedisAdapter
29+
"""
30+
self._pluggable_adapter = pluggable_adapter
31+
self._prefix = "SPLITIO.rbsegment.${segmen_name}"
32+
self._rb_segments_till_prefix = "SPLITIO.rbsegments.till"
33+
if prefix is not None:
34+
self._prefix = prefix + "." + self._prefix
35+
self._rb_segments_till_prefix = prefix + "." + self._rb_segments_till_prefix
36+
37+
def get(self, segment_name):
38+
"""
39+
Retrieve a rule based segment.
40+
41+
:param segment_name: Name of the segment to fetch.
42+
:type segment_name: str
43+
44+
:rtype: str
45+
"""
46+
pass
47+
48+
def get_change_number(self):
49+
"""
50+
Retrieve latest rule based segment change number.
51+
52+
:rtype: int
53+
"""
54+
pass
55+
56+
def contains(self, segment_names):
57+
"""
58+
Return whether the segments exists in rule based segment in cache.
59+
60+
:param segment_names: segment name to validate.
61+
:type segment_names: str
62+
63+
:return: True if segment names exists. False otherwise.
64+
:rtype: bool
65+
"""
66+
pass
67+
68+
def get_segment_names(self):
69+
"""
70+
Retrieve a list of all excluded segments names.
71+
72+
:return: List of segment names.
73+
:rtype: list(str)
74+
"""
75+
pass
76+
77+
def update(self, to_add, to_delete, new_change_number):
78+
"""
79+
Update rule based segment..
80+
81+
:param to_add: List of rule based segment. to add
82+
:type to_add: list[splitio.models.rule_based_segments.RuleBasedSegment]
83+
:param to_delete: List of rule based segment. to delete
84+
:type to_delete: list[splitio.models.rule_based_segments.RuleBasedSegment]
85+
:param new_change_number: New change number.
86+
:type new_change_number: int
87+
"""
88+
raise NotImplementedError('Only redis-consumer mode is supported.')
89+
90+
def get_large_segment_names(self):
91+
"""
92+
Retrieve a list of all excluded large segments names.
93+
94+
:return: List of segment names.
95+
:rtype: list(str)
96+
"""
97+
pass
98+
99+
class PluggableRuleBasedSegmentsStorage(PluggableRuleBasedSegmentsStorageBase):
100+
"""RedPluggable storage for rule based segments."""
101+
102+
def __init__(self, pluggable_adapter, prefix=None):
103+
"""
104+
Class constructor.
105+
106+
:param redis_client: Redis client or compliant interface.
107+
:type redis_client: splitio.storage.adapters.redis.RedisAdapter
108+
"""
109+
PluggableRuleBasedSegmentsStorageBase.__init__(self, pluggable_adapter, prefix)
110+
111+
def get(self, segment_name):
112+
"""
113+
Retrieve a rule based segment.
114+
115+
:param segment_name: Name of the segment to fetch.
116+
:type segment_name: str
117+
118+
:rtype: str
119+
"""
120+
try:
121+
rb_segment = self._pluggable_adapter.get(self._prefix.format(segment_name=segment_name))
122+
if not rb_segment:
123+
return None
124+
125+
return rule_based_segments.from_raw(rb_segment)
126+
127+
except Exception:
128+
_LOGGER.error('Error getting rule based segment from storage')
129+
_LOGGER.debug('Error: ', exc_info=True)
130+
return None
131+
132+
def get_change_number(self):
133+
"""
134+
Retrieve latest rule based segment change number.
135+
136+
:rtype: int
137+
"""
138+
try:
139+
return self._pluggable_adapter.get(self._rb_segments_till_prefix)
140+
141+
except Exception:
142+
_LOGGER.error('Error getting change number in rule based segment storage')
143+
_LOGGER.debug('Error: ', exc_info=True)
144+
return None
145+
146+
def contains(self, segment_names):
147+
"""
148+
Return whether the segments exists in rule based segment in cache.
149+
150+
:param segment_names: segment name to validate.
151+
:type segment_names: str
152+
153+
:return: True if segment names exists. False otherwise.
154+
:rtype: bool
155+
"""
156+
return set(segment_names).issubset(self.get_segment_names())
157+
158+
def get_segment_names(self):
159+
"""
160+
Retrieve a list of all rule based segments names.
161+
162+
:return: List of segment names.
163+
:rtype: list(str)
164+
"""
165+
try:
166+
keys = []
167+
for key in self._pluggable_adapter.get_keys_by_prefix(self._prefix[:-self._RB_SEGMENT_NAME_LENGTH]):
168+
if key[-self._TILL_LENGTH:] != 'till':
169+
keys.append(key[len(self._prefix[:-self._RB_SEGMENT_NAME_LENGTH]):])
170+
return keys
171+
172+
except Exception:
173+
_LOGGER.error('Error getting rule based segments names from storage')
174+
_LOGGER.debug('Error: ', exc_info=True)
175+
return None
176+
177+
class PluggableRuleBasedSegmentsStorageAsync(RuleBasedSegmentsStorage):
178+
"""RedPluggable storage for rule based segments."""
179+
180+
def __init__(self, pluggable_adapter, prefix=None):
181+
"""
182+
Class constructor.
183+
184+
:param redis_client: Redis client or compliant interface.
185+
:type redis_client: splitio.storage.adapters.redis.RedisAdapter
186+
"""
187+
PluggableRuleBasedSegmentsStorageBase.__init__(self, pluggable_adapter, prefix)
188+
189+
async def get(self, segment_name):
190+
"""
191+
Retrieve a rule based segment.
192+
193+
:param segment_name: Name of the segment to fetch.
194+
:type segment_name: str
195+
196+
:rtype: str
197+
"""
198+
try:
199+
rb_segment = await self._pluggable_adapter.get(self._prefix.format(segment_name=segment_name))
200+
if not rb_segment:
201+
return None
202+
203+
return rule_based_segments.from_raw(rb_segment)
204+
205+
except Exception:
206+
_LOGGER.error('Error getting rule based segment from storage')
207+
_LOGGER.debug('Error: ', exc_info=True)
208+
return None
209+
210+
async def get_change_number(self):
211+
"""
212+
Retrieve latest rule based segment change number.
213+
214+
:rtype: int
215+
"""
216+
try:
217+
return await self._pluggable_adapter.get(self._rb_segments_till_prefix)
218+
219+
except Exception:
220+
_LOGGER.error('Error getting change number in rule based segment storage')
221+
_LOGGER.debug('Error: ', exc_info=True)
222+
return None
223+
224+
async def contains(self, segment_names):
225+
"""
226+
Return whether the segments exists in rule based segment in cache.
227+
228+
:param segment_names: segment name to validate.
229+
:type segment_names: str
230+
231+
:return: True if segment names exists. False otherwise.
232+
:rtype: bool
233+
"""
234+
return await set(segment_names).issubset(self.get_segment_names())
235+
236+
async def get_segment_names(self):
237+
"""
238+
Retrieve a list of all rule based segments names.
239+
240+
:return: List of segment names.
241+
:rtype: list(str)
242+
"""
243+
try:
244+
keys = []
245+
for key in await self._pluggable_adapter.get_keys_by_prefix(self._prefix[:-self._RB_SEGMENT_NAME_LENGTH]):
246+
if key[-self._TILL_LENGTH:] != 'till':
247+
keys.append(key[len(self._prefix[:-self._RB_SEGMENT_NAME_LENGTH]):])
248+
return keys
249+
250+
except Exception:
251+
_LOGGER.error('Error getting rule based segments names from storage')
252+
_LOGGER.debug('Error: ', exc_info=True)
253+
return None
254+
17255
class PluggableSplitStorageBase(SplitStorage):
18256
"""InMemory implementation of a feature flag storage."""
19257

@@ -90,7 +328,7 @@ def update(self, to_add, to_delete, new_change_number):
90328
:param new_change_number: New change number.
91329
:type new_change_number: int
92330
"""
93-
# pass
331+
pass
94332
# try:
95333
# split = self.get(feature_flag_name)
96334
# if not split:

0 commit comments

Comments
 (0)