Skip to content

Commit 21b6eb8

Browse files
authored
Merge pull request #282 from splitio/fix-redis-impressions-count
fixed impressions.count key and ttl in redis
2 parents 4c339ea + 77363bb commit 21b6eb8

File tree

6 files changed

+30
-46
lines changed

6 files changed

+30
-46
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
9.2.1 (Nov 29, 2022)
2+
- Changed redis record type for impressions counts from list using rpush to hashed key using hincrby
3+
14
9.2.0 (Oct 14, 2022)
25
- Added a new impressions mode for the SDK called NONE , to be used in factory when there is no desire to capture impressions on an SDK factory to feed Split's analytics engine. Running NONE mode, the SDK will only capture unique keys evaluated for a particular feature flag instead of full blown impressions
36

splitio/engine/impressions/adapters.py

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ def __init__(self, redis_client):
6666
:type telemtry_http_client: splitio.api.telemetry.TelemetryAPI
6767
"""
6868
self._redis_client = redis_client
69+
self.pipe = self._redis_client.pipeline()
70+
6971

7072
def record_unique_keys(self, uniques):
7173
"""
@@ -88,13 +90,17 @@ def flush_counters(self, to_send):
8890
"""
8991
post the impression counters to redis.
9092
91-
:param uniques: unique keys disctionary
92-
:type uniques: Dictionary {'feature1': set(), 'feature2': set(), .. }
93+
:param to_send: unique keys disctionary
94+
:type to_send: Dictionary {'feature1': set(), 'feature2': set(), .. }
9395
"""
94-
bulk_counts = self._build_counters(to_send)
9596
try:
96-
inserted = self._redis_client.rpush(self.IMP_COUNT_QUEUE_KEY, *bulk_counts)
97-
self._expire_keys(self.IMP_COUNT_QUEUE_KEY, self.IMP_COUNT_KEY_DEFAULT_TTL, inserted, len(bulk_counts))
97+
resulted = 0
98+
counted = 0
99+
for pf_count in to_send:
100+
self.pipe.hincrby(self.IMP_COUNT_QUEUE_KEY, pf_count.feature + "::" + str(pf_count.timeframe), pf_count.count)
101+
counted += pf_count.count
102+
resulted = sum(self.pipe.execute())
103+
self._expire_keys(self.IMP_COUNT_QUEUE_KEY, self.IMP_COUNT_KEY_DEFAULT_TTL, resulted, counted)
98104
return True
99105
except RedisAdapterException:
100106
_LOGGER.error('Something went wrong when trying to add counters to redis')
@@ -124,23 +130,3 @@ def _uniques_formatter(self, uniques):
124130
:rtype: json
125131
"""
126132
return [json.dumps({'f': feature, 'ks': list(keys)}) for feature, keys in uniques.items()]
127-
128-
def _build_counters(self, counters):
129-
"""
130-
Build an impression bulk formatted as the API expects it.
131-
132-
:param counters: List of impression counters per feature.
133-
:type counters: list[splitio.engine.impressions.Counter.CountPerFeature]
134-
135-
:return: dict with list of impression count dtos
136-
:rtype: dict
137-
"""
138-
return json.dumps({
139-
'pf': [
140-
{
141-
'f': pf_count.feature,
142-
'm': pf_count.timeframe,
143-
'rc': pf_count.count
144-
} for pf_count in counters
145-
]
146-
})

splitio/storage/adapters/redis.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,13 @@ def hget(self, name, key):
241241
except RedisError as exc:
242242
raise RedisAdapterException('Error executing hget operation') from exc
243243

244+
def hincrby(self, name, key, amount=1):
245+
"""Mimic original redis function but using user custom prefix."""
246+
try:
247+
return self._decorated.hincrby(self._prefix_helper.add_prefix(name), key, amount)
248+
except RedisError as exc:
249+
raise RedisAdapterException('Error executing hincrby operation') from exc
250+
244251
def incr(self, name, amount=1):
245252
"""Mimic original redis function but using user custom prefix."""
246253
try:
@@ -323,6 +330,10 @@ def incr(self, name, amount=1):
323330
"""Mimic original redis function but using user custom prefix."""
324331
self._pipe.incr(self._prefix_helper.add_prefix(name), amount)
325332

333+
def hincrby(self, name, key, amount=1):
334+
"""Mimic original redis function but using user custom prefix."""
335+
self._pipe.hincrby(self._prefix_helper.add_prefix(name), key, amount)
336+
326337
def execute(self):
327338
"""Mimic original redis function but using user custom prefix."""
328339
try:

splitio/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '9.2.0'
1+
__version__ = '9.2.1-rc'

tests/client/test_factory.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def test_redis_client_creation(self, mocker):
100100
assert adapter == factory._get_storage('impressions')._redis
101101
assert adapter == factory._get_storage('events')._redis
102102

103-
assert strict_redis_mock.mock_calls == [mocker.call(
103+
assert strict_redis_mock.mock_calls[0] == mocker.call(
104104
host='some_host',
105105
port=1234,
106106
db=1,
@@ -121,8 +121,8 @@ def test_redis_client_creation(self, mocker):
121121
ssl_certfile='some_cert_file',
122122
ssl_cert_reqs='some_cert_req',
123123
ssl_ca_certs='some_ca_cert',
124-
max_connections=999
125-
)]
124+
max_connections=999,
125+
)
126126
assert factory._labels_enabled is False
127127
assert isinstance(factory._recorder, PipelinedRecorder)
128128
assert isinstance(factory._recorder._impressions_manager, ImpressionsManager)

tests/engine/test_send_adapters.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,6 @@ def test_uniques_formatter(self, mocker):
5656
for i in range(0,1):
5757
assert(sorted(ast.literal_eval(sender_adapter._uniques_formatter(uniques)[i])["ks"]) == sorted(formatted[i]["ks"]))
5858

59-
def test_build_counters(self, mocker):
60-
"""Test formatting counters dict to json."""
61-
62-
counters = [
63-
Counter.CountPerFeature('f1', 123, 2),
64-
Counter.CountPerFeature('f2', 123, 123),
65-
]
66-
formatted = [
67-
{'f': 'f1', 'm': 123, 'rc': 2},
68-
{'f': 'f2', 'm': 123, 'rc': 123},
69-
]
70-
71-
sender_adapter = RedisSenderAdapter(mocker.Mock())
72-
for i in range(0,1):
73-
assert(sorted(ast.literal_eval(sender_adapter._build_counters(counters))['pf'][i]) == sorted(formatted[i]))
74-
7559
@mock.patch('splitio.storage.adapters.redis.RedisAdapter.rpush')
7660
def test_record_unique_keys(self, mocker):
7761
"""Test sending unique keys."""
@@ -85,7 +69,7 @@ def test_record_unique_keys(self, mocker):
8569

8670
assert(mocker.called)
8771

88-
@mock.patch('splitio.storage.adapters.redis.RedisAdapter.rpush')
72+
@mock.patch('splitio.storage.adapters.redis.RedisPipelineAdapter.hincrby')
8973
def test_flush_counters(self, mocker):
9074
"""Test sending counters."""
9175

0 commit comments

Comments
 (0)