Skip to content

Commit 4120b8e

Browse files
authored
ref(redis) Don't use redis-blaster for snowflake ids v3 (#104114)
Redo of the changes in #103967 along with a removal of the skip introduced in #104057. With the keys used for snowflakes aligned (as of #104075) we shouldn't have flaky results anymore. Refs INFRENG-210
1 parent 7d243b2 commit 4120b8e

File tree

3 files changed

+19
-10
lines changed

3 files changed

+19
-10
lines changed

src/sentry/conf/server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ def env(
195195
SENTRY_HYBRIDCLOUD_DELETIONS_REDIS_CLUSTER = "default"
196196
SENTRY_SESSION_STORE_REDIS_CLUSTER = "default"
197197
SENTRY_AUTH_IDPMIGRATION_REDIS_CLUSTER = "default"
198+
SENTRY_SNOWFLAKE_REDIS_CLUSTER = "default"
198199

199200
# Hosts that are allowed to use system token authentication.
200201
# http://en.wikipedia.org/wiki/Reserved_IP_addresses

src/sentry/utils/snowflake.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
from django.conf import settings
99
from django.db import IntegrityError, router, transaction
1010
from django.db.models import Model
11-
from redis.client import StrictRedis
1211
from rest_framework import status
1312
from rest_framework.exceptions import APIException
13+
from sentry_redis_tools.clients import RedisCluster, StrictRedis
1414

1515
from sentry.db.postgres.transactions import enforce_constraints
1616
from sentry.types.region import RegionContextError, get_local_region
17+
from sentry.utils import redis
1718

1819
if TYPE_CHECKING:
1920
from sentry.db.models.base import Model as BaseModel
@@ -139,14 +140,16 @@ def generate_snowflake_id(redis_key: str) -> int:
139140
return snowflake_id
140141

141142

142-
def get_redis_cluster(redis_key: str) -> StrictRedis[str]:
143-
from sentry.utils import redis
143+
def get_redis_cluster() -> RedisCluster[str] | StrictRedis[str]:
144+
return redis.redis_clusters.get(settings.SENTRY_SNOWFLAKE_REDIS_CLUSTER)
144145

145-
return redis.clusters.get("default").get_local_client_for_key(redis_key)
146+
147+
def get_timestamp_redis_key(redis_key: str, timestamp: int) -> str:
148+
return f"snowflakeid:{redis_key}:{str(timestamp)}"
146149

147150

148151
def get_sequence_value_from_redis(redis_key: str, starting_timestamp: int) -> tuple[int, int]:
149-
cluster = get_redis_cluster(redis_key)
152+
cluster = get_redis_cluster()
150153

151154
# this is the amount we want to lookback for previous timestamps
152155
# the below is more of a safety net if starting_timestamp is ever
@@ -156,14 +159,16 @@ def get_sequence_value_from_redis(redis_key: str, starting_timestamp: int) -> tu
156159
for i in range(time_range):
157160
timestamp = starting_timestamp - i
158161

162+
timestamp_redis_key = get_timestamp_redis_key(redis_key, timestamp)
163+
159164
# We are decreasing the value by 1 each time since the incr operation in redis
160165
# initializes the counter at 1. For our region sequences, we want the value to
161166
# be from 0-15 and not 1-16
162-
sequence_value = cluster.incr(str(timestamp))
167+
sequence_value = cluster.incr(timestamp_redis_key)
163168
sequence_value -= 1
164169

165170
if sequence_value == 0:
166-
cluster.expire(str(timestamp), int(_TTL.total_seconds()))
171+
cluster.expire(timestamp_redis_key, int(_TTL.total_seconds()))
167172

168173
if sequence_value < MAX_AVAILABLE_REGION_SEQUENCES:
169174
return timestamp, sequence_value

tests/sentry/utils/test_snowflake.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
SnowflakeBitSegment,
2121
generate_snowflake_id,
2222
get_redis_cluster,
23+
get_timestamp_redis_key,
2324
uses_snowflake_id,
2425
)
2526

@@ -64,14 +65,16 @@ def test_generate_correct_ids_with_region_sequence(self) -> None:
6465

6566
@freeze_time(CURRENT_TIME)
6667
def test_out_of_region_sequences(self) -> None:
67-
cluster = get_redis_cluster("test_redis_key")
68+
cluster = get_redis_cluster()
6869
current_timestamp = int(datetime.now().timestamp() - settings.SENTRY_SNOWFLAKE_EPOCH_START)
70+
redis_key = "test_redis_key"
71+
6972
for i in range(int(_TTL.total_seconds())):
7073
timestamp = current_timestamp - i
71-
cluster.set(str(timestamp), 16)
74+
cluster.set(get_timestamp_redis_key(redis_key, timestamp), 16)
7275

7376
with pytest.raises(Exception) as context:
74-
generate_snowflake_id("test_redis_key")
77+
generate_snowflake_id(redis_key)
7578

7679
assert str(context.value) == "No available ID"
7780

0 commit comments

Comments
 (0)