Skip to content

Commit

Permalink
Fixed search fetch crashing because of server taking too long for api…
Browse files Browse the repository at this point in the history
… request logs (#2178)

* fix: fixed search fetch crashing because of server taking too long for api request logs
  • Loading branch information
MueezKhan246 authored Jul 26, 2024
1 parent 65b0a86 commit da45a02
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Unreleased
----------
* nothing unreleased

[4.21.9]
---------
* fix: fixed search fetch crashing because of server taking too long for api request logs.

[4.21.8]
---------
* fix: fixed 500 error for search filter for api request logs in admin view.
Expand Down
2 changes: 1 addition & 1 deletion enterprise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Your project description goes here.
"""

__version__ = "4.21.8"
__version__ = "4.21.9"
27 changes: 18 additions & 9 deletions integrated_channels/integrated_channel/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,10 @@ class IntegratedChannelAPIRequestLogAdmin(admin.ModelAdmin):
"status_code",
]
search_fields = [
"status_code",
"enterprise_customer__name",
"enterprise_customer__uuid",
"enterprise_customer_configuration_id",
"endpoint",
"time_taken",
"response_body",
"payload",
"enterprise_customer__name__icontains",
"enterprise_customer__uuid__iexact",
"enterprise_customer_configuration_id__iexact",
"endpoint__icontains",
]
readonly_fields = [
"status_code",
Expand All @@ -122,12 +118,25 @@ class IntegratedChannelAPIRequestLogAdmin(admin.ModelAdmin):
"response_body",
"payload",
]
list_filter = ('status_code',)

list_per_page = 20

def get_queryset(self, request):
"""
Optimize queryset by selecting related 'enterprise_customer' and limiting fields.
"""
queryset = super().get_queryset(request)
return queryset.select_related('enterprise_customer')
return queryset.select_related('enterprise_customer').only(
'id',
'endpoint',
'enterprise_customer_id',
'time_taken',
'status_code',
'enterprise_customer__name',
'enterprise_customer__uuid',
'enterprise_customer_configuration_id'
)

class Meta:
model = IntegratedChannelAPIRequestLogs
77 changes: 77 additions & 0 deletions tests/test_admin/test_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Tests for the IntegratedChannelAPIRequest admin module in `edx-enterprise`.
"""

from django.contrib.admin.sites import AdminSite
from django.db import connection
from django.test import TestCase
from django.test.utils import CaptureQueriesContext

from integrated_channels.integrated_channel.admin import IntegratedChannelAPIRequestLogAdmin
from integrated_channels.integrated_channel.models import IntegratedChannelAPIRequestLogs
from test_utils import factories


class IntegratedChannelAPIRequestLogAdminTest(TestCase):
"""
Test the admin functionality for the IntegratedChannelAPIRequestLogs model.
"""

def setUp(self):
"""
Set up the test environment by creating a test admin instance and sample data.
"""
self.site = AdminSite()
self.admin = IntegratedChannelAPIRequestLogAdmin(IntegratedChannelAPIRequestLogs, self.site)

self.enterprise_customer = factories.EnterpriseCustomerFactory(name='Test Enterprise')
self.log_entry = IntegratedChannelAPIRequestLogs.objects.create(
enterprise_customer=self.enterprise_customer,
enterprise_customer_configuration_id=1,
endpoint="http://test.com",
payload="test payload",
time_taken=1.0,
status_code=200,
response_body="test response"
)

def test_get_queryset_optimization(self):
"""
Test that the get_queryset method optimizes query by using select_related and only selecting specified fields.
"""
request = None

with CaptureQueriesContext(connection) as queries:
queryset = self.admin.get_queryset(request)

list(queryset)

self.assertEqual(len(queries), 1)

query = queries[0]['sql']
self.assertIn('integrated_channel_integratedchannelapirequestlogs', query)
self.assertIn('enterprise_enterprisecustomer', query)

self.assertIn('"integrated_channel_integratedchannelapirequestlogs"."id"', query)
self.assertIn('"integrated_channel_integratedchannelapirequestlogs"."endpoint"', query)
self.assertIn('"integrated_channel_integratedchannelapirequestlogs"."enterprise_customer_id"', query)
self.assertIn('"integrated_channel_integratedchannelapirequestlogs"."time_taken"', query)
self.assertIn('"integrated_channel_integratedchannelapirequestlogs"."status_code"', query)
self.assertIn('"enterprise_enterprisecustomer"."name"', query)
self.assertIn('"enterprise_enterprisecustomer"."uuid"', query)
self.assertIn(
'"integrated_channel_integratedchannelapirequestlogs"."enterprise_customer_configuration_id"', query
)

self.assertNotIn('payload', query)
self.assertNotIn('response_body', query)

log_entry = queryset.get(id=self.log_entry.id)
self.assertEqual(log_entry.endpoint, "http://test.com")
self.assertEqual(log_entry.enterprise_customer.name, "Test Enterprise")

# Verify that accessing an unselected field causes an additional query
with CaptureQueriesContext(connection) as queries:
_ = log_entry.payload

self.assertEqual(len(queries), 1, "Accessing unselected field should cause exactly one additional query")

0 comments on commit da45a02

Please sign in to comment.