Skip to content

Commit 33c6c63

Browse files
ref(uptime): Simplify consumer with one-to-one proj_sub <-> sub (take 2) (#90261)
This reverts commit f08b664 with fixes to handle when there is no project_subscription for a uptime_subscription
1 parent 8e9655f commit 33c6c63

File tree

3 files changed

+48
-56
lines changed

3 files changed

+48
-56
lines changed

src/sentry/uptime/consumers/results_consumer.py

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@
3333
UptimeSubscription,
3434
UptimeSubscriptionRegion,
3535
get_detector,
36-
get_project_subscriptions_for_uptime_subscription,
36+
get_project_subscription_for_uptime_subscription,
3737
get_top_hosting_provider_names,
3838
load_regions_for_uptime_subscription,
3939
)
4040
from sentry.uptime.subscriptions.subscriptions import (
4141
check_and_update_regions,
4242
delete_uptime_detector,
43+
remove_uptime_subscription_if_unused,
4344
update_project_uptime_subscription,
4445
)
4546
from sentry.uptime.subscriptions.tasks import (
@@ -293,29 +294,17 @@ def handle_result(self, subscription: UptimeSubscription | None, result: CheckRe
293294

294295
try_check_and_update_regions(subscription, result, subscription_regions)
295296

296-
project_subscriptions = get_project_subscriptions_for_uptime_subscription(subscription.id)
297+
project_subscription = get_project_subscription_for_uptime_subscription(subscription.id)
297298

298-
cluster = _get_cluster()
299-
last_updates: list[str | None] = cluster.mget(
300-
build_last_update_key(sub) for sub in project_subscriptions
301-
)
299+
# Nothing to do if there's an orphaned project subscription
300+
if not project_subscription:
301+
remove_uptime_subscription_if_unused(subscription)
302+
return
302303

303-
for last_update_raw, project_subscription in zip(last_updates, project_subscriptions):
304-
last_update_ms = 0 if last_update_raw is None else int(last_update_raw)
305-
self.handle_result_for_project(
306-
project_subscription,
307-
result,
308-
last_update_ms,
309-
metric_tags.copy(),
310-
)
304+
cluster = _get_cluster()
305+
last_update_raw: str | None = cluster.get(build_last_update_key(project_subscription))
306+
last_update_ms = 0 if last_update_raw is None else int(last_update_raw)
311307

312-
def handle_result_for_project(
313-
self,
314-
project_subscription: ProjectUptimeSubscription,
315-
result: CheckResult,
316-
last_update_ms: int,
317-
metric_tags: dict[str, str],
318-
):
319308
if features.has(
320309
"organizations:uptime-detailed-logging", project_subscription.project.organization
321310
):

src/sentry/uptime/models.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,15 @@ def get_top_hosting_provider_names(limit: int) -> set[str]:
266266
recalculate=False,
267267
cache_ttl=timedelta(hours=4),
268268
)
269-
def get_project_subscriptions_for_uptime_subscription(
269+
def get_project_subscription_for_uptime_subscription(
270270
uptime_subscription_id: int,
271-
) -> list[ProjectUptimeSubscription]:
272-
return list(
273-
ProjectUptimeSubscription.objects.filter(
274-
uptime_subscription_id=uptime_subscription_id
275-
).select_related("project", "project__organization")
276-
)
271+
) -> ProjectUptimeSubscription | None:
272+
try:
273+
return ProjectUptimeSubscription.objects.select_related(
274+
"project", "project__organization"
275+
).get(uptime_subscription_id=uptime_subscription_id)
276+
except ProjectUptimeSubscription.DoesNotExist:
277+
return None
277278

278279

279280
@cache_func_for_models(

tests/sentry/uptime/consumers/test_results_consumer.py

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from sentry.conf.types import kafka_definition
2424
from sentry.conf.types.uptime import UptimeRegionConfig
25-
from sentry.constants import DataCategory, ObjectStatus
25+
from sentry.constants import DataCategory
2626
from sentry.models.group import Group, GroupStatus
2727
from sentry.testutils.abstract import Abstract
2828
from sentry.testutils.helpers.datetime import freeze_time
@@ -157,6 +157,25 @@ def test(self):
157157
assert self.project_subscription.uptime_status == UptimeStatus.FAILED
158158
assert self.project_subscription.uptime_subscription.uptime_status == UptimeStatus.FAILED
159159

160+
def test_does_nothing_when_missing_project_subscription(self):
161+
self.project_subscription.delete()
162+
163+
result = self.create_uptime_result(
164+
self.subscription.subscription_id,
165+
scheduled_check_time=datetime.now() - timedelta(minutes=5),
166+
)
167+
with (
168+
self.feature(["organizations:uptime", "organizations:uptime-create-issues"]),
169+
mock.patch("sentry.remote_subscriptions.consumers.result_consumer.logger") as logger,
170+
mock.patch(
171+
"sentry.uptime.consumers.results_consumer.remove_uptime_subscription_if_unused"
172+
) as mock_remove_uptime_subscription_if_unused,
173+
):
174+
# Does not produce an error
175+
self.send_result(result)
176+
assert not logger.exception.called
177+
mock_remove_uptime_subscription_if_unused.assert_called_with(self.subscription)
178+
160179
def test_restricted_host_provider_id(self):
161180
"""
162181
Test that we do NOT create an issue when the host provider identifier
@@ -446,32 +465,6 @@ def test_no_subscription(self):
446465
"default", UptimeSubscription(subscription_id=subscription_id), "delete", None
447466
)
448467

449-
def test_multiple_project_subscriptions_with_disabled(self):
450-
"""
451-
Tests that we do not process results for disabled project subscriptions
452-
"""
453-
# Second disabled project subscription
454-
self.create_project_uptime_subscription(
455-
uptime_subscription=self.subscription,
456-
project=self.create_project(),
457-
status=ObjectStatus.DISABLED,
458-
)
459-
result = self.create_uptime_result(self.subscription.subscription_id)
460-
461-
with (
462-
mock.patch("sentry.uptime.consumers.results_consumer.metrics") as metrics,
463-
self.feature(["organizations:uptime", "organizations:uptime-create-issues"]),
464-
):
465-
self.send_result(result)
466-
# We only process a single project result, the other is dropped,
467-
# there should be only one handle_result_for_project metric call
468-
handle_result_calls = [
469-
c
470-
for c in metrics.incr.mock_calls
471-
if c[1][0] == "uptime.result_processor.handle_result_for_project"
472-
]
473-
assert len(handle_result_calls) == 1
474-
475468
def test_organization_feature_disabled(self):
476469
"""
477470
Tests that we do not process results for disabled project subscriptions
@@ -1063,6 +1056,7 @@ def test_check_and_update_regions(self):
10631056
subscription_id=uuid.UUID(int=5).hex,
10641057
region_slugs=["region1"],
10651058
)
1059+
self.create_project_uptime_subscription(uptime_subscription=sub)
10661060
self.run_check_and_update_region_test(
10671061
sub,
10681062
["region1", "region2"],
@@ -1093,6 +1087,7 @@ def test_check_and_update_regions_active_shadow(self):
10931087
subscription_id=uuid.UUID(int=5).hex,
10941088
region_slugs=["region1", "region2"],
10951089
)
1090+
self.create_project_uptime_subscription(uptime_subscription=sub)
10961091
self.run_check_and_update_region_test(
10971092
sub,
10981093
["region1", "region2"],
@@ -1119,6 +1114,7 @@ def test_check_and_update_regions_larger_interval(self):
11191114
region_slugs=["region1"],
11201115
interval_seconds=UptimeSubscription.IntervalSeconds.ONE_HOUR,
11211116
)
1117+
self.create_project_uptime_subscription(uptime_subscription=hour_sub)
11221118
self.run_check_and_update_region_test(
11231119
hour_sub,
11241120
["region1", "region2"],
@@ -1140,6 +1136,7 @@ def test_check_and_update_regions_larger_interval(self):
11401136
region_slugs=["region1"],
11411137
interval_seconds=UptimeSubscription.IntervalSeconds.FIVE_MINUTES,
11421138
)
1139+
self.create_project_uptime_subscription(uptime_subscription=five_min_sub)
11431140
self.run_check_and_update_region_test(
11441141
five_min_sub,
11451142
["region1", "region2"],
@@ -1188,6 +1185,7 @@ def test_check_and_update_regions_larger_interval(self):
11881185
region_slugs=["region1"],
11891186
interval_seconds=UptimeSubscription.IntervalSeconds.FIVE_MINUTES,
11901187
)
1188+
self.create_project_uptime_subscription(uptime_subscription=five_min_sub)
11911189
self.run_check_and_update_region_test(
11921190
five_min_sub,
11931191
["region1", "region2"],
@@ -1206,8 +1204,10 @@ def test_check_and_update_regions_larger_interval(self):
12061204

12071205
def test_check_and_update_regions_removes_disabled(self):
12081206
sub = self.create_uptime_subscription(
1209-
subscription_id=uuid.UUID(int=5).hex, region_slugs=["region1", "region2"]
1207+
subscription_id=uuid.UUID(int=5).hex,
1208+
region_slugs=["region1", "region2"],
12101209
)
1210+
self.create_project_uptime_subscription(uptime_subscription=sub)
12111211
self.run_check_and_update_region_test(
12121212
sub,
12131213
["region1", "region2"],
@@ -1259,6 +1259,7 @@ def test_parallel(self) -> None:
12591259
subscription_2 = self.create_uptime_subscription(
12601260
subscription_id=uuid.uuid4().hex, interval_seconds=300, url="http://santry.io"
12611261
)
1262+
self.create_project_uptime_subscription(uptime_subscription=subscription_2)
12621263

12631264
result_1 = self.create_uptime_result(
12641265
self.subscription.subscription_id,
@@ -1310,6 +1311,7 @@ def test_parallel_grouping(self, mock_process_group) -> None:
13101311
subscription_2 = self.create_uptime_subscription(
13111312
subscription_id=uuid.uuid4().hex, interval_seconds=300, url="http://santry.io"
13121313
)
1314+
self.create_project_uptime_subscription(uptime_subscription=subscription_2)
13131315

13141316
result_1 = self.create_uptime_result(
13151317
self.subscription.subscription_id,

0 commit comments

Comments
 (0)