cache dashboard query (#16165)

This causes an expensive query and the view sometimes called excessively
by the UI.  Memoize per unique user and params (time period) for 15s.
This commit is contained in:
Elijah DeLee 2025-12-03 13:03:39 -05:00 committed by GitHub
parent be30a75c4f
commit 711b018ae7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -97,6 +97,7 @@ from awx.main.utils import (
from awx.main.utils.encryption import encrypt_value from awx.main.utils.encryption import encrypt_value
from awx.main.utils.filters import SmartFilter from awx.main.utils.filters import SmartFilter
from awx.main.utils.plugins import compute_cloud_inventory_sources from awx.main.utils.plugins import compute_cloud_inventory_sources
from awx.main.utils.common import memoize
from awx.main.redact import UriCleaner from awx.main.redact import UriCleaner
from awx.api.permissions import ( from awx.api.permissions import (
JobTemplateCallbackPermission, JobTemplateCallbackPermission,
@ -271,7 +272,24 @@ class DashboardJobsGraphView(APIView):
period = request.query_params.get('period', 'month') period = request.query_params.get('period', 'month')
job_type = request.query_params.get('job_type', 'all') job_type = request.query_params.get('job_type', 'all')
user_unified_jobs = get_user_queryset(request.user, models.UnifiedJob).exclude(launch_type='sync') user_id = getattr(request.user, 'id', None) or 0
try:
payload = self._compute_dashboard_jobs_graph(user_id, period, job_type)
except ParseError as exc:
return Response({'error': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
return Response(payload)
@staticmethod
@memoize(ttl=15)
def _compute_dashboard_jobs_graph(user_id, period, job_type):
# Debug log when there is a cache miss
logger.debug('DashboardJobsGraphView cache miss: user_id=%s period=%s job_type=%s', user_id, period, job_type)
# Validate period. Raise exception to let caller return 400 error in response
if period not in ('month', 'two_weeks', 'week', 'day'):
raise ParseError(_('Unknown period "%s"') % str(period))
user = models.User.objects.get(pk=user_id) if user_id else None
user_unified_jobs = get_user_queryset(user, models.UnifiedJob).exclude(launch_type='sync')
success_query = user_unified_jobs.filter(status='successful') success_query = user_unified_jobs.filter(status='successful')
failed_query = user_unified_jobs.filter(status='failed') failed_query = user_unified_jobs.filter(status='failed')
@ -305,8 +323,6 @@ class DashboardJobsGraphView(APIView):
elif period == 'day': elif period == 'day':
start = end - dateutil.relativedelta.relativedelta(days=1) start = end - dateutil.relativedelta.relativedelta(days=1)
interval = 'hour' interval = 'hour'
else:
return Response({'error': _('Unknown period "%s"') % str(period)}, status=status.HTTP_400_BAD_REQUEST)
dashboard_data = {"jobs": {"successful": [], "failed": [], "canceled": [], "error": []}} dashboard_data = {"jobs": {"successful": [], "failed": [], "canceled": [], "error": []}}
@ -358,7 +374,7 @@ class DashboardJobsGraphView(APIView):
canceled_list.append([time.mktime(date.timetuple()), data_c.get(date, 0)]) canceled_list.append([time.mktime(date.timetuple()), data_c.get(date, 0)])
error_list.append([time.mktime(date.timetuple()), data_e.get(date, 0)]) error_list.append([time.mktime(date.timetuple()), data_e.get(date, 0)])
return Response(dashboard_data) return dashboard_data
class InstanceList(ListCreateAPIView): class InstanceList(ListCreateAPIView):