Skip to content

Commit 4f6597b

Browse files
authored
ref(uptime): move uptime helper functions to utility file (#102105)
Sorry. But these are functions that have moved around a couple of times due to circular dependency issues, so let's just push them into their own file. I also looked at most of the major files in uptime to see if there were any other obvious candidates to be moved here, but from what I can tell, it's relatively tidy. (I also put back the get_cluster() call I had to inline, in a preceding PR.)
1 parent 15d0971 commit 4f6597b

File tree

13 files changed

+82
-81
lines changed

13 files changed

+82
-81
lines changed

src/sentry/uptime/autodetect/ranking.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@
44
from datetime import datetime, timedelta
55
from typing import TYPE_CHECKING
66

7-
from django.conf import settings
8-
from redis.client import StrictRedis
9-
from rediscluster import RedisCluster
10-
117
from sentry.constants import UPTIME_AUTODETECTION
128
from sentry.uptime.models import get_active_auto_monitor_count_for_org
139
from sentry.uptime.subscriptions.subscriptions import (
1410
MAX_AUTO_SUBSCRIPTIONS_PER_ORG,
1511
MaxUrlsForDomainReachedException,
1612
check_url_limits,
1713
)
18-
from sentry.utils import metrics, redis
14+
from sentry.uptime.utils import get_cluster
15+
from sentry.utils import metrics
1916

2017
if TYPE_CHECKING:
2118
from sentry.models.organization import Organization
@@ -37,10 +34,6 @@
3734
KEY_EXPIRY = ORGANIZATION_FLUSH_FREQUENCY * 2
3835

3936

40-
def _get_cluster() -> RedisCluster | StrictRedis:
41-
return redis.redis_clusters.get(settings.SENTRY_UPTIME_DETECTOR_CLUSTER)
42-
43-
4437
def add_base_url_to_rank(project: Project, base_url: str):
4538
"""
4639
Takes a project and valid base url and stores ranking information about it in Redis.
@@ -59,7 +52,7 @@ def add_base_url_to_rank(project: Project, base_url: str):
5952
larger than `RANKED_MAX_SIZE`. That shouldn't cause us problems, and is preferable to
6053
trimming it on every call.
6154
"""
62-
cluster = _get_cluster()
55+
cluster = get_cluster()
6356
org_projects_key = build_org_projects_key(project.organization)
6457
pipeline = cluster.pipeline()
6558
pipeline.zincrby(org_projects_key, 1, str(project.id))
@@ -91,7 +84,7 @@ def get_candidate_projects_for_org(org: Organization) -> list[tuple[int, int]]:
9184
Project ids are sorted by `total_urls_seen` desc.
9285
"""
9386
key = build_org_projects_key(org)
94-
cluster = _get_cluster()
87+
cluster = get_cluster()
9588
return [
9689
(int(project_id), count)
9790
for project_id, count in cluster.zrange(
@@ -105,7 +98,7 @@ def delete_candidate_projects_for_org(org: Organization) -> None:
10598
Deletes candidate projects related to the organization that have seen urls.
10699
"""
107100
key = build_org_projects_key(org)
108-
cluster = _get_cluster()
101+
cluster = get_cluster()
109102
cluster.delete(key)
110103

111104

@@ -115,7 +108,7 @@ def get_candidate_urls_for_project(project: Project, limit=5) -> list[tuple[str,
115108
`times_url_seen` desc.
116109
"""
117110
key = get_project_base_url_rank_key(project)
118-
cluster = _get_cluster()
111+
cluster = get_cluster()
119112
candidate_urls = cluster.zrange(key, 0, -1, desc=True, withscores=True, score_cast_func=int)
120113
urls = []
121114
for candidate_url, url_count in candidate_urls:
@@ -134,7 +127,7 @@ def delete_candidate_urls_for_project(project: Project) -> None:
134127
Deletes all current candidate rules for a project.
135128
"""
136129
key = get_project_base_url_rank_key(project)
137-
cluster = _get_cluster()
130+
cluster = get_cluster()
138131
cluster.delete(key)
139132

140133

@@ -166,7 +159,7 @@ def get_organization_bucket(bucket: datetime) -> set[int]:
166159
that have projects that have seen urls.
167160
"""
168161
key = get_organization_bucket_key_for_datetime(bucket)
169-
cluster = _get_cluster()
162+
cluster = get_cluster()
170163
return {int(organization_id) for organization_id in cluster.smembers(key)}
171164

172165

@@ -175,7 +168,7 @@ def delete_organization_bucket(bucket: datetime) -> None:
175168
Delete all organizations from a specific datetime bucket.
176169
"""
177170
key = get_organization_bucket_key_for_datetime(bucket)
178-
cluster = _get_cluster()
171+
cluster = get_cluster()
179172
cluster.delete(key)
180173

181174

src/sentry/uptime/autodetect/result_handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
from sentry import audit_log
1313
from sentry.uptime.autodetect.notifications import send_auto_detected_notifications
14-
from sentry.uptime.autodetect.ranking import _get_cluster
1514
from sentry.uptime.autodetect.tasks import set_failed_url
1615
from sentry.uptime.models import UptimeSubscription, get_audit_log_data
1716
from sentry.uptime.subscriptions.subscriptions import (
@@ -20,6 +19,7 @@
2019
update_uptime_detector,
2120
)
2221
from sentry.uptime.types import UptimeMonitorMode
22+
from sentry.uptime.utils import get_cluster
2323
from sentry.utils import metrics
2424
from sentry.utils.audit import create_system_audit_entry
2525
from sentry.workflow_engine.models.detector import Detector
@@ -52,7 +52,7 @@ def handle_onboarding_result(
5252
metric_tags: dict[str, str],
5353
) -> None:
5454
if result["status"] == CHECKSTATUS_FAILURE:
55-
redis = _get_cluster()
55+
redis = get_cluster()
5656
key = build_onboarding_failure_key(detector)
5757
pipeline = redis.pipeline()
5858
pipeline.incr(key)

src/sentry/uptime/autodetect/tasks.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from sentry.tasks.base import instrumented_task
1515
from sentry.taskworker.namespaces import uptime_tasks
1616
from sentry.uptime.autodetect.ranking import (
17-
_get_cluster,
1817
delete_candidate_projects_for_org,
1918
delete_candidate_urls_for_project,
2019
delete_organization_bucket,
@@ -31,6 +30,7 @@
3130
is_url_auto_monitored_for_project,
3231
)
3332
from sentry.uptime.types import UptimeMonitorMode
33+
from sentry.uptime.utils import get_cluster
3434
from sentry.utils import metrics
3535
from sentry.utils.hashlib import md5_text
3636
from sentry.utils.locking import UnableToAcquireLock
@@ -67,7 +67,7 @@ def schedule_autodetections():
6767
)
6868
try:
6969
with lock.acquire():
70-
cluster = _get_cluster()
70+
cluster = get_cluster()
7171
last_processed = cluster.get(LAST_PROCESSED_KEY)
7272
if last_processed is None:
7373
last_processed = timezone.now().replace(second=0, microsecond=0)
@@ -260,7 +260,7 @@ def monitor_url_for_project(project: Project, url: str) -> Detector:
260260

261261
def is_failed_url(url: str) -> bool:
262262
key = get_failed_url_key(url)
263-
return _get_cluster().exists(key) == 1
263+
return get_cluster().exists(key) == 1
264264

265265

266266
def set_failed_url(url: str) -> None:
@@ -269,7 +269,7 @@ def set_failed_url(url: str) -> None:
269269
"""
270270
key = get_failed_url_key(url)
271271
# TODO: Jitter the expiry here, so we don't retry all at the same time.
272-
_get_cluster().set(key, 1, ex=FAILED_URL_RETRY_FREQ)
272+
get_cluster().set(key, 1, ex=FAILED_URL_RETRY_FREQ)
273273

274274

275275
def get_failed_url_key(url: str) -> str:

src/sentry/uptime/consumers/results_consumer.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
ResultProcessor,
1919
ResultsStrategyFactory,
2020
)
21-
from sentry.uptime.autodetect.ranking import _get_cluster
2221
from sentry.uptime.autodetect.result_handler import handle_onboarding_result
2322
from sentry.uptime.consumers.eap_producer import produce_eap_uptime_result
2423
from sentry.uptime.grouptype import UptimePacketValue
@@ -30,8 +29,6 @@
3029
load_regions_for_uptime_subscription,
3130
)
3231
from sentry.uptime.subscriptions.subscriptions import (
33-
build_last_seen_interval_key,
34-
build_last_update_key,
3532
check_and_update_regions,
3633
disable_uptime_detector,
3734
remove_uptime_subscription_if_unused,
@@ -41,6 +38,7 @@
4138
update_remote_uptime_subscription,
4239
)
4340
from sentry.uptime.types import UptimeMonitorMode
41+
from sentry.uptime.utils import build_last_seen_interval_key, build_last_update_key, get_cluster
4442
from sentry.utils import metrics
4543
from sentry.workflow_engine.models.data_source import DataPacket
4644
from sentry.workflow_engine.models.detector import Detector
@@ -277,7 +275,7 @@ def handle_result(self, subscription: UptimeSubscription | None, result: CheckRe
277275
sample_rate=1.0,
278276
)
279277

280-
cluster = _get_cluster()
278+
cluster = get_cluster()
281279
last_update_key = build_last_update_key(detector)
282280
last_update_raw: str | None = cluster.get(last_update_key)
283281
last_update_ms = 0 if last_update_raw is None else int(last_update_raw)

src/sentry/uptime/grouptype.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
from sentry.types.group import PriorityLevel
1616
from sentry.uptime.endpoints.validators import UptimeDomainCheckFailureValidator
1717
from sentry.uptime.models import UptimeSubscription
18-
from sentry.uptime.subscriptions.subscriptions import build_fingerprint
1918
from sentry.uptime.types import GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, UptimeMonitorMode
19+
from sentry.uptime.utils import build_fingerprint
2020
from sentry.utils import metrics
2121
from sentry.workflow_engine.handlers.detector.base import DetectorOccurrence, EventData
2222
from sentry.workflow_engine.handlers.detector.stateful import (

src/sentry/uptime/subscriptions/subscriptions.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import logging
22
from collections.abc import Sequence
33

4-
from django.conf import settings
54
from django.db import router, transaction
65
from sentry_kafka_schemas.schema_types.uptime_results_v1 import (
76
CHECKSTATUS_FAILURE,
@@ -40,7 +39,7 @@
4039
GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE,
4140
UptimeMonitorMode,
4241
)
43-
from sentry.utils import redis
42+
from sentry.uptime.utils import build_fingerprint, build_last_update_key, get_cluster
4443
from sentry.utils.db import atomic_transaction
4544
from sentry.utils.not_set import NOT_SET, NotSet, default_if_not_set
4645
from sentry.utils.outcomes import Outcome
@@ -58,22 +57,6 @@
5857
MAX_MONITORS_PER_DOMAIN = 100
5958

6059

61-
def build_last_update_key(detector: Detector) -> str:
62-
return f"project-sub-last-update:detector:{detector.id}"
63-
64-
65-
def build_last_seen_interval_key(detector: Detector) -> str:
66-
return f"project-sub-last-seen-interval:detector:{detector.id}"
67-
68-
69-
def build_detector_fingerprint_component(detector: Detector) -> str:
70-
return f"uptime-detector:{detector.id}"
71-
72-
73-
def build_fingerprint(detector: Detector) -> list[str]:
74-
return [build_detector_fingerprint_component(detector)]
75-
76-
7760
def resolve_uptime_issue(detector: Detector) -> None:
7861
"""
7962
Sends an update to the issue platform to resolve the uptime issue for this
@@ -474,7 +457,7 @@ def disable_uptime_detector(detector: Detector, skip_quotas: bool = False):
474457
# start from a good state
475458
detector_state.update(state=DetectorPriorityLevel.OK, is_triggered=False)
476459

477-
cluster = redis.redis_clusters.get(settings.SENTRY_UPTIME_DETECTOR_CLUSTER)
460+
cluster = get_cluster()
478461
last_update_key = build_last_update_key(detector)
479462
cluster.delete(last_update_key)
480463

src/sentry/uptime/utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from django.conf import settings
2+
from redis.client import StrictRedis
3+
from rediscluster import RedisCluster
4+
5+
from sentry.utils import redis
6+
from sentry.workflow_engine.models.detector import Detector
7+
8+
9+
def build_last_update_key(detector: Detector) -> str:
10+
return f"project-sub-last-update:detector:{detector.id}"
11+
12+
13+
def build_last_seen_interval_key(detector: Detector) -> str:
14+
return f"project-sub-last-seen-interval:detector:{detector.id}"
15+
16+
17+
def build_detector_fingerprint_component(detector: Detector) -> str:
18+
return f"uptime-detector:{detector.id}"
19+
20+
21+
def build_fingerprint(detector: Detector) -> list[str]:
22+
return [build_detector_fingerprint_component(detector)]
23+
24+
25+
def get_cluster() -> RedisCluster | StrictRedis:
26+
return redis.redis_clusters.get(settings.SENTRY_UPTIME_DETECTOR_CLUSTER)

tests/sentry/tasks/test_post_process.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@
7575
from sentry.testutils.skips import requires_snuba
7676
from sentry.types.activity import ActivityType
7777
from sentry.types.group import GroupSubStatus, PriorityLevel
78-
from sentry.uptime.autodetect.ranking import _get_cluster, get_organization_bucket_key
78+
from sentry.uptime.autodetect.ranking import get_organization_bucket_key
79+
from sentry.uptime.utils import get_cluster
7980
from sentry.users.services.user.service import user_service
8081
from sentry.utils import json
8182
from sentry.utils.cache import cache
@@ -2314,7 +2315,7 @@ def test_user_reports_no_shim_if_group_exists_on_report(
23142315
class DetectBaseUrlsForUptimeTestMixin(BasePostProgressGroupMixin):
23152316
def assert_organization_key(self, organization: Organization, exists: bool) -> None:
23162317
key = get_organization_bucket_key(organization)
2317-
cluster = _get_cluster()
2318+
cluster = get_cluster()
23182319
assert exists == cluster.sismember(key, str(organization.id))
23192320

23202321
def test_uptime_detection_feature_url(self) -> None:

tests/sentry/uptime/autodetect/test_detector.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
from sentry.testutils.cases import UptimeTestCase
33
from sentry.testutils.helpers.options import override_options
44
from sentry.uptime.autodetect.detector import autodetect_base_url_for_project
5-
from sentry.uptime.autodetect.ranking import _get_cluster, get_organization_bucket_key
5+
from sentry.uptime.autodetect.ranking import get_organization_bucket_key
6+
from sentry.uptime.utils import get_cluster
67

78

89
class DetectBaseUrlForProjectTest(UptimeTestCase):
910
def assert_organization_key(self, organization: Organization, exists: bool) -> None:
1011
key = get_organization_bucket_key(organization)
11-
cluster = _get_cluster()
12+
cluster = get_cluster()
1213
assert exists == cluster.sismember(key, str(organization.id))
1314

1415
def test(self) -> None:

tests/sentry/uptime/autodetect/test_ranking.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from sentry.models.project import Project
66
from sentry.testutils.cases import UptimeTestCase
77
from sentry.uptime.autodetect.ranking import (
8-
_get_cluster,
98
add_base_url_to_rank,
109
build_org_projects_key,
1110
delete_candidate_urls_for_project,
@@ -17,14 +16,15 @@
1716
should_autodetect_for_organization,
1817
should_autodetect_for_project,
1918
)
19+
from sentry.uptime.utils import get_cluster
2020

2121

2222
class AddBaseUrlToRankTest(UptimeTestCase):
2323
def assert_project_count(
2424
self, project: Project, count: int | None, expiry: int | None
2525
) -> int | None:
2626
key = build_org_projects_key(project.organization)
27-
cluster = _get_cluster()
27+
cluster = get_cluster()
2828
if count is None:
2929
assert not cluster.zscore(key, str(project.id))
3030
return None
@@ -36,7 +36,7 @@ def assert_url_count(
3636
self, project: Project, url: str, count: int | None, expiry: int | None
3737
) -> int | None:
3838
key = get_project_base_url_rank_key(project)
39-
cluster = _get_cluster()
39+
cluster = get_cluster()
4040
if count is None:
4141
assert cluster.zscore(key, url) is None
4242
return None
@@ -45,7 +45,7 @@ def assert_url_count(
4545
return self.check_expiry(key, expiry)
4646

4747
def check_expiry(self, key: str, expiry: int | None) -> int:
48-
cluster = _get_cluster()
48+
cluster = get_cluster()
4949
ttl = cluster.ttl(key)
5050
if expiry is None:
5151
assert ttl > 0
@@ -94,7 +94,7 @@ def test_trim(self) -> None:
9494
url_1 = "https://sentry.io"
9595
url_2 = "https://sentry.sentry.io"
9696
url_3 = "https://santry.sentry.io"
97-
cluster = _get_cluster()
97+
cluster = get_cluster()
9898
add_base_url_to_rank(self.project, url_1)
9999
add_base_url_to_rank(self.project, url_1)
100100
add_base_url_to_rank(self.project, url_1)

0 commit comments

Comments
 (0)