Skip to content

Commit 9e98c19

Browse files
authored
fix(spans-migration): make script to migrate the AM1 metrics queries to transactions (#112621)
welp another migration 😞 turns out we have a bunch of generic metrics alerts on am1 💀 but they really shouldn't be on generic metrics cause am1 doesn't have dynamic sampling (oh and we're killing metrics backend so lovely) so these should all be transactions alerts. Gonna migrate these because lowkey they haven't even been working for a while and who knows maybe this will help fix some other issues we have.
1 parent 4f234a5 commit 9e98c19

File tree

2 files changed

+467
-0
lines changed

2 files changed

+467
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import logging
2+
3+
import sentry_sdk
4+
from django.db import router
5+
6+
from sentry import features
7+
from sentry.explore.translation.alerts_translation import _get_old_query_info
8+
from sentry.incidents.utils.types import DATA_SOURCE_SNUBA_QUERY_SUBSCRIPTION
9+
from sentry.snuba.dataset import Dataset
10+
from sentry.snuba.models import (
11+
QuerySubscription,
12+
SnubaQuery,
13+
SnubaQueryEventType,
14+
)
15+
from sentry.snuba.subscriptions import bulk_update_snuba_subscriptions
16+
from sentry.utils.db import atomic_transaction
17+
from sentry.workflow_engine.models.data_source import DataSource
18+
19+
logger = logging.getLogger(__name__)
20+
21+
22+
def snapshot_snuba_query(snuba_query: SnubaQuery):
23+
if not snuba_query.query_snapshot and snuba_query.dataset in [
24+
Dataset.PerformanceMetrics.value,
25+
]:
26+
query_snapshot = {
27+
"metrics_to_transactions": True,
28+
}
29+
snuba_query.query_snapshot = query_snapshot
30+
snuba_query.save()
31+
32+
return snuba_query
33+
34+
35+
def translate_am1_metrics_detector_and_update_subscription_in_snuba(snuba_query: SnubaQuery):
36+
query_subscription_qs = QuerySubscription.objects.filter(
37+
snuba_query_id=snuba_query.id,
38+
status__in=[QuerySubscription.Status.ACTIVE.value, QuerySubscription.Status.UPDATING.value],
39+
)
40+
query_subscription = query_subscription_qs.first()
41+
42+
if not query_subscription:
43+
logger.info("No active query subscription found for snuba query %s", snuba_query.id)
44+
return
45+
46+
try:
47+
data_source: DataSource = DataSource.objects.get(
48+
source_id=str(query_subscription.id), type=DATA_SOURCE_SNUBA_QUERY_SUBSCRIPTION
49+
)
50+
except DataSource.DoesNotExist as e:
51+
logger.info("Data source not found for snuba query %s", snuba_query.id)
52+
sentry_sdk.capture_exception(e)
53+
return
54+
if not features.has(
55+
"organizations:migrate-am1-metrics-alerts-to-transactions", data_source.organization
56+
):
57+
logger.info("Feature flag not enabled")
58+
return
59+
60+
snapshot_snuba_query(snuba_query)
61+
62+
snapshot = snuba_query.query_snapshot
63+
if not snapshot and snuba_query.dataset == Dataset.PerformanceMetrics.value:
64+
logger.info("No snapshot created for snuba query %s", snuba_query.id)
65+
return
66+
67+
if snapshot and snapshot.get("user_updated"):
68+
logger.info(
69+
"Skipping migration for user-updated query", extra={"snuba_query_id": snuba_query.id}
70+
)
71+
return
72+
73+
old_query_type, old_dataset, old_query, old_aggregate = _get_old_query_info(snuba_query)
74+
75+
snuba_query.dataset = Dataset.Transactions.value
76+
77+
with atomic_transaction(
78+
using=(
79+
router.db_for_write(SnubaQuery),
80+
router.db_for_write(SnubaQueryEventType),
81+
router.db_for_write(QuerySubscription),
82+
)
83+
):
84+
snuba_query.save()
85+
86+
query_subscriptions = list(snuba_query.subscriptions.all())
87+
try:
88+
bulk_update_snuba_subscriptions(
89+
query_subscriptions, old_query_type, old_dataset, old_aggregate, old_query
90+
)
91+
except Exception as e:
92+
logger.info(
93+
"Query not migrated: error updating subscriptions in snuba",
94+
extra={"snuba_query_id": snuba_query.id, "error": e},
95+
)
96+
raise
97+
98+
logger.info(
99+
"Query successfully migrated to transactions", extra={"snuba_query_id": snuba_query.id}
100+
)
101+
return
102+
103+
104+
def rollback_am1_metrics_detector_query_and_update_subscription_in_snuba(snuba_query: SnubaQuery):
105+
# querying for updating as well just in case the subscription gets stuck in updating
106+
query_subscription_qs = QuerySubscription.objects.filter(
107+
snuba_query_id=snuba_query.id,
108+
status__in=[QuerySubscription.Status.ACTIVE.value, QuerySubscription.Status.UPDATING.value],
109+
)
110+
query_subscription = query_subscription_qs.first()
111+
112+
if not query_subscription:
113+
logger.info("No active query subscription found for snuba query %s", snuba_query.id)
114+
return
115+
116+
try:
117+
data_source: DataSource = DataSource.objects.get(
118+
source_id=str(query_subscription.id), type=DATA_SOURCE_SNUBA_QUERY_SUBSCRIPTION
119+
)
120+
except DataSource.DoesNotExist as e:
121+
logger.info("Data source not found for snuba query %s", snuba_query.id)
122+
sentry_sdk.capture_exception(e)
123+
return
124+
125+
if not features.has(
126+
"organizations:migrate-am1-metrics-alerts-to-transactions", data_source.organization
127+
):
128+
logger.info("Feature flag not enabled")
129+
return
130+
131+
snapshot = snuba_query.query_snapshot
132+
is_snapshot_am1_metrics = (
133+
snapshot is not None and snapshot.get("metrics_to_transactions", False) is True
134+
)
135+
136+
if not is_snapshot_am1_metrics:
137+
logger.info("No snapshot found for snuba query %s", snuba_query.id)
138+
return
139+
140+
if snapshot and snapshot.get("user_updated"):
141+
logger.info(
142+
"Skipping rollback for user-updated query", extra={"snuba_query_id": snuba_query.id}
143+
)
144+
return
145+
146+
if snuba_query.dataset == Dataset.PerformanceMetrics.value:
147+
logger.info("Query already migrated to metrics", extra={"snuba_query_id": snuba_query.id})
148+
return
149+
150+
if snuba_query.dataset != Dataset.Transactions.value:
151+
logger.info(
152+
"Query is not the correct dataset to rollback", extra={"snuba_query_id": snuba_query.id}
153+
)
154+
return
155+
156+
old_query_type, old_dataset, old_query, old_aggregate = _get_old_query_info(snuba_query)
157+
158+
with atomic_transaction(
159+
using=(
160+
router.db_for_write(SnubaQuery),
161+
router.db_for_write(SnubaQueryEventType),
162+
router.db_for_write(QuerySubscription),
163+
)
164+
):
165+
snuba_query.update(
166+
dataset=Dataset.PerformanceMetrics.value,
167+
)
168+
169+
query_subscriptions = list(snuba_query.subscriptions.all())
170+
try:
171+
bulk_update_snuba_subscriptions(
172+
query_subscriptions, old_query_type, old_dataset, old_aggregate, old_query
173+
)
174+
except Exception as e:
175+
logger.info(
176+
"Query not rolled back: error updating subscriptions in snuba",
177+
extra={"snuba_query_id": snuba_query.id, "error": e},
178+
)
179+
raise
180+
181+
logger.info(
182+
"Query successfully rolled back to legacy", extra={"snuba_query_id": snuba_query.id}
183+
)
184+
return

0 commit comments

Comments
 (0)