Skip to content

Commit

Permalink
Optimize duplicate queries occurring in AlertGroupFilter (#1809)
Browse files Browse the repository at this point in the history
# What this PR does

In `AlertGroupFilter` we currently have 11 duplicate queries which add
~1-2secs of unecessary request latency to `GET
/api/internal/v1/alertgroups` calls.
![Screenshot 2023-04-20 at 17 57
49](https://user-images.githubusercontent.com/9406895/233589341-de5e53ca-f10b-4038-ad68-a857d1643bf2.png)



The queries originate from the `queryset` callable arguments on several
of the fields of the `AlertGroupFilter` class. These callables basically
filter down their respective querysets to include only objects that
belong to the currently authenticated user's organization.

The duplicate queries are
- 2 queries to fetch integrations
- 2 queries to fetch escalation chains
- 10 queries to fetch users

At the moment, this PR is still a draft and doesn't work as intended.
It's based off of [a suggestion from this
discussion](carltongibson/django-filter#1572 (comment))
in the `django-filter` repo. See [this DjangoCon
talk](https://youtu.be/e52S1SjuUeM?t=841) for more context.

---------

Co-authored-by: Ildar Iskhakov <[email protected]>
  • Loading branch information
joeyorlando and iskhakov committed Apr 26, 2023
1 parent 23c7a6f commit 52ff041
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add 2, 3 and 6 hours silence options

## Fixed

- Optimize duplicate queries occurring in AlertGroupFilter by @joeyorlando ([1809](https://github.com/grafana/oncall/pull/1809))

## v1.2.15 (2023-04-24)

### Fixed
Expand Down
41 changes: 33 additions & 8 deletions engine/apps/api/views/alert_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,31 @@ def get_user_queryset(request):
return User.objects.filter(organization=request.user.organization).distinct()


class AlertGroupFilterBackend(filters.DjangoFilterBackend):
"""
See here for more context on how this works
https://github.com/carltongibson/django-filter/discussions/1572
https://youtu.be/e52S1SjuUeM?t=841
"""

def get_filterset(self, request, queryset, view):
filterset = super().get_filterset(request, queryset, view)

filterset.form.fields["integration"].queryset = get_integration_queryset(request)
filterset.form.fields["escalation_chain"].queryset = get_escalation_chain_queryset(request)

user_queryset = get_user_queryset(request)

filterset.form.fields["silenced_by"].queryset = user_queryset
filterset.form.fields["acknowledged_by"].queryset = user_queryset
filterset.form.fields["resolved_by"].queryset = user_queryset
filterset.form.fields["invitees_are"].queryset = user_queryset
filterset.form.fields["involved_users_are"].queryset = user_queryset

return filterset


class AlertGroupFilter(DateRangeFilterMixin, ByTeamModelFieldFilterMixin, ModelFieldFilterMixin, filters.FilterSet):
"""
Examples of possible date formats here https://docs.djangoproject.com/en/1.9/ref/settings/#datetime-input-formats
Expand All @@ -69,19 +94,19 @@ class AlertGroupFilter(DateRangeFilterMixin, ByTeamModelFieldFilterMixin, ModelF
silenced_at = filters.CharFilter(field_name="silenced_at", method=DateRangeFilterMixin.filter_date_range.__name__)
silenced_by = filters.ModelMultipleChoiceFilter(
field_name="silenced_by_user",
queryset=get_user_queryset,
queryset=None,
to_field_name="public_primary_key",
method=ModelFieldFilterMixin.filter_model_field.__name__,
)
integration = filters.ModelMultipleChoiceFilter(
field_name="channel_filter__alert_receive_channel",
queryset=get_integration_queryset,
queryset=None,
to_field_name="public_primary_key",
method=ModelFieldFilterMixin.filter_model_field.__name__,
)
escalation_chain = filters.ModelMultipleChoiceFilter(
field_name="channel_filter__escalation_chain",
queryset=get_escalation_chain_queryset,
queryset=None,
to_field_name="public_primary_key",
method=ModelFieldFilterMixin.filter_model_field.__name__,
)
Expand All @@ -90,21 +115,21 @@ class AlertGroupFilter(DateRangeFilterMixin, ByTeamModelFieldFilterMixin, ModelF
)
resolved_by = filters.ModelMultipleChoiceFilter(
field_name="resolved_by_user",
queryset=get_user_queryset,
queryset=None,
to_field_name="public_primary_key",
method=ModelFieldFilterMixin.filter_model_field.__name__,
)
acknowledged_by = filters.ModelMultipleChoiceFilter(
field_name="acknowledged_by_user",
queryset=get_user_queryset,
queryset=None,
to_field_name="public_primary_key",
method=ModelFieldFilterMixin.filter_model_field.__name__,
)
invitees_are = filters.ModelMultipleChoiceFilter(
queryset=get_user_queryset, to_field_name="public_primary_key", method="filter_invitees_are"
queryset=None, to_field_name="public_primary_key", method="filter_invitees_are"
)
involved_users_are = filters.ModelMultipleChoiceFilter(
queryset=get_user_queryset, to_field_name="public_primary_key", method="filter_by_involved_users"
queryset=None, to_field_name="public_primary_key", method="filter_by_involved_users"
)
with_resolution_note = filters.BooleanFilter(method="filter_with_resolution_note")
mine = filters.BooleanFilter(method="filter_mine")
Expand Down Expand Up @@ -270,7 +295,7 @@ class AlertGroupView(

pagination_class = TwentyFiveCursorPaginator

filter_backends = [SearchFilter, filters.DjangoFilterBackend]
filter_backends = [SearchFilter, AlertGroupFilterBackend]
search_fields = ["public_primary_key", "inside_organization_number", "web_title_cache"]

filterset_class = AlertGroupFilter
Expand Down

0 comments on commit 52ff041

Please sign in to comment.