Skip to content

Commit 6faf0ae

Browse files
authored
♻️ ref(metric alerts): refactor _build_incident_query_builder and _calculate_incident_time_range (#86014)
refactory work to make notification action work with metric alert registry. here, i remove the `windowed_stats` param because its completely unused, and hoist FK lookups from `_build_incident_query_builder` and `_calculate_incident_time_range`
1 parent cbe289a commit 6faf0ae

File tree

1 file changed

+74
-53
lines changed

1 file changed

+74
-53
lines changed

src/sentry/incidents/logic.py

Lines changed: 74 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -270,25 +270,49 @@ def _unpack_organization(alert_rule: AlertRule) -> Organization:
270270
return organization
271271

272272

273-
def _build_incident_query_builder(
274-
incident: Incident,
275-
entity_subscription: EntitySubscription,
276-
start: datetime | None = None,
277-
end: datetime | None = None,
278-
windowed_stats: bool = False,
273+
@dataclass
274+
class BaseMetricIssueQueryParams:
275+
snuba_query: SnubaQuery
276+
date_started: datetime
277+
current_end_date: datetime
278+
organization: Organization
279+
280+
281+
@dataclass
282+
class CalculateOpenPeriodTimeRangeParams(BaseMetricIssueQueryParams):
283+
start_arg: datetime | None = None
284+
end_arg: datetime | None = None
285+
286+
287+
@dataclass
288+
class BuildMetricQueryBuilderParams(BaseMetricIssueQueryParams):
289+
project_ids: list[int]
290+
entity_subscription: EntitySubscription
291+
start_arg: datetime | None = None
292+
end_arg: datetime | None = None
293+
294+
295+
def _build_metric_query_builder(
296+
params: BuildMetricQueryBuilderParams,
279297
) -> BaseQueryBuilder:
280-
snuba_query = _unpack_snuba_query(incident.alert_rule)
281-
start, end = _calculate_incident_time_range(incident, start, end, windowed_stats=windowed_stats)
282-
project_ids = list(
283-
IncidentProject.objects.filter(incident=incident).values_list("project_id", flat=True)
298+
start, end = _calculate_open_period_time_range(
299+
CalculateOpenPeriodTimeRangeParams(
300+
snuba_query=params.snuba_query,
301+
date_started=params.date_started,
302+
current_end_date=params.current_end_date,
303+
organization=params.organization,
304+
start_arg=params.start_arg,
305+
end_arg=params.end_arg,
306+
)
284307
)
285-
query_builder = entity_subscription.build_query_builder(
286-
query=snuba_query.query,
287-
project_ids=project_ids,
288-
environment=snuba_query.environment,
308+
309+
query_builder = params.entity_subscription.build_query_builder(
310+
query=params.snuba_query.query,
311+
project_ids=params.project_ids,
312+
environment=params.snuba_query.environment,
289313
params={
290-
"organization_id": incident.organization_id,
291-
"project_id": project_ids,
314+
"organization_id": params.organization.id,
315+
"project_id": params.project_ids,
292316
"start": start,
293317
"end": end,
294318
},
@@ -309,37 +333,19 @@ def _build_incident_query_builder(
309333
return query_builder
310334

311335

312-
def _calculate_incident_time_range(
313-
incident: Incident,
314-
start_arg: datetime | None = None,
315-
end_arg: datetime | None = None,
316-
windowed_stats: bool = False,
336+
def _calculate_open_period_time_range(
337+
params: CalculateOpenPeriodTimeRangeParams,
317338
) -> tuple[datetime, datetime]:
318-
snuba_query = _unpack_snuba_query(incident.alert_rule)
319-
time_window = snuba_query.time_window if incident.alert_rule is not None else 60
339+
time_window = params.snuba_query.time_window
320340
time_window_delta = timedelta(seconds=time_window)
321-
start = (incident.date_started - time_window_delta) if start_arg is None else start_arg
322-
end = (incident.current_end_date + time_window_delta) if end_arg is None else end_arg
323-
if windowed_stats:
324-
now = django_timezone.now()
325-
end = start + timedelta(seconds=time_window * (WINDOWED_STATS_DATA_POINTS / 2))
326-
start = start - timedelta(seconds=time_window * (WINDOWED_STATS_DATA_POINTS / 2))
327-
if end > now:
328-
end = now
329-
330-
# If the incident ended already, 'now' could be greater than we'd like
331-
# which would result in showing too many data points after an incident ended.
332-
# This depends on when the task to process snapshots runs.
333-
# To resolve that, we ensure that the end is never greater than the date
334-
# an incident ended + the smaller of time_window*10 or 10 days.
335-
latest_end_date = incident.current_end_date + min(
336-
timedelta(seconds=time_window * 10), timedelta(days=10)
337-
)
338-
end = min(end, latest_end_date)
339-
340-
start = end - timedelta(seconds=time_window * WINDOWED_STATS_DATA_POINTS)
341+
start = (
342+
(params.date_started - time_window_delta) if params.start_arg is None else params.start_arg
343+
)
344+
end = (
345+
(params.current_end_date + time_window_delta) if params.end_arg is None else params.end_arg
346+
)
341347

342-
retention = quotas.backend.get_event_retention(organization=incident.organization) or 90
348+
retention = quotas.backend.get_event_retention(organization=params.organization) or 90
343349
start = max(
344350
start.replace(tzinfo=timezone.utc),
345351
datetime.now(timezone.utc) - timedelta(days=retention),
@@ -353,7 +359,6 @@ def get_incident_aggregates(
353359
incident: Incident,
354360
start: datetime | None = None,
355361
end: datetime | None = None,
356-
windowed_stats: bool = False,
357362
) -> dict[str, float | int]:
358363
"""
359364
Calculates aggregate stats across the life of an incident, or the provided range.
@@ -363,13 +368,20 @@ def get_incident_aggregates(
363368
snuba_query,
364369
incident.organization_id,
365370
)
366-
if entity_subscription.dataset == Dataset.EventsAnalyticsPlatform:
367-
start, end = _calculate_incident_time_range(
368-
incident, start, end, windowed_stats=windowed_stats
369-
)
371+
project_ids = list(
372+
IncidentProject.objects.filter(incident=incident).values_list("project_id", flat=True)
373+
)
370374

371-
project_ids = list(
372-
IncidentProject.objects.filter(incident=incident).values_list("project_id", flat=True)
375+
if entity_subscription.dataset == Dataset.EventsAnalyticsPlatform:
376+
start, end = _calculate_open_period_time_range(
377+
CalculateOpenPeriodTimeRangeParams(
378+
snuba_query=snuba_query,
379+
date_started=incident.date_started,
380+
current_end_date=incident.current_end_date,
381+
organization=incident.organization,
382+
start_arg=start,
383+
end_arg=end,
384+
)
373385
)
374386

375387
params = SnubaParams(
@@ -404,8 +416,17 @@ def get_incident_aggregates(
404416
)
405417
raise
406418
else:
407-
query_builder = _build_incident_query_builder(
408-
incident, entity_subscription, start, end, windowed_stats
419+
query_builder = _build_metric_query_builder(
420+
BuildMetricQueryBuilderParams(
421+
snuba_query=snuba_query,
422+
organization=incident.organization,
423+
project_ids=project_ids,
424+
entity_subscription=entity_subscription,
425+
date_started=incident.date_started,
426+
current_end_date=incident.current_end_date,
427+
start_arg=start,
428+
end_arg=end,
429+
)
409430
)
410431
try:
411432
results = query_builder.run_query(referrer="incidents.get_incident_aggregates")

0 commit comments

Comments
 (0)