feat(events): add cursor infinite event feed
This commit is contained in:
43
backend/jobs/tests/test_api.py
Normal file
43
backend/jobs/tests/test_api.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import pytest
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from jobs.services import create_job
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_global_events_use_cursor_pagination():
|
||||
create_job(job_type="demo.success")
|
||||
create_job(job_type="demo.fail")
|
||||
create_job(job_type="demo.slow")
|
||||
|
||||
response = APIClient().get("/api/job-events/?limit=2")
|
||||
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["next"] is not None
|
||||
assert body["previous"] is None
|
||||
assert len(body["results"]) == 2
|
||||
assert body["results"][0]["id"] > body["results"][1]["id"]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_global_events_next_cursor_returns_older_events():
|
||||
create_job(job_type="demo.success")
|
||||
create_job(job_type="demo.fail")
|
||||
create_job(job_type="demo.slow")
|
||||
client = APIClient()
|
||||
first_response = client.get("/api/job-events/?limit=2")
|
||||
first_body = first_response.json()
|
||||
parsed_next = urlparse(first_body["next"])
|
||||
next_path = f"{parsed_next.path}?{parsed_next.query}"
|
||||
|
||||
next_response = client.get(next_path)
|
||||
|
||||
assert next_response.status_code == 200
|
||||
body = next_response.json()
|
||||
assert body["next"] is None
|
||||
assert body["previous"] is not None
|
||||
assert len(body["results"]) == 1
|
||||
assert body["results"][0]["id"] < first_body["results"][1]["id"]
|
||||
@@ -1,6 +1,7 @@
|
||||
from django.db import connection
|
||||
from rest_framework import generics, status
|
||||
from rest_framework.exceptions import NotFound, ValidationError
|
||||
from rest_framework.pagination import CursorPagination
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
@@ -9,6 +10,13 @@ from jobs.serializers import JobCreateSerializer, JobEventSerializer, JobSeriali
|
||||
from jobs.services import create_job, job_stats, retry_failed_job
|
||||
|
||||
|
||||
class JobEventCursorPagination(CursorPagination):
|
||||
page_size = 50
|
||||
page_size_query_param = "limit"
|
||||
max_page_size = 200
|
||||
ordering = "-id"
|
||||
|
||||
|
||||
class HealthAPIView(APIView):
|
||||
def get(self, request):
|
||||
try:
|
||||
@@ -63,21 +71,17 @@ class JobEventsAPIView(APIView):
|
||||
|
||||
class GlobalJobEventsAPIView(APIView):
|
||||
def get(self, request):
|
||||
queryset = JobEvent.objects.order_by("id")
|
||||
after_id = request.query_params.get("after_id")
|
||||
queryset = JobEvent.objects.order_by("-id")
|
||||
event_type = request.query_params.get("type")
|
||||
job_id = request.query_params.get("job_id")
|
||||
if after_id:
|
||||
queryset = queryset.filter(id__gt=after_id)
|
||||
if event_type:
|
||||
queryset = queryset.filter(type=event_type)
|
||||
if job_id:
|
||||
queryset = queryset.filter(job_id=job_id)
|
||||
try:
|
||||
limit = min(int(request.query_params.get("limit", "100")), 500)
|
||||
except ValueError as exc:
|
||||
raise ValidationError({"limit": "Must be an integer."}) from exc
|
||||
return Response(JobEventSerializer(queryset[:limit], many=True).data)
|
||||
|
||||
paginator = JobEventCursorPagination()
|
||||
page = paginator.paginate_queryset(queryset, request, view=self)
|
||||
return paginator.get_paginated_response(JobEventSerializer(page, many=True).data)
|
||||
|
||||
|
||||
class JobStatsAPIView(APIView):
|
||||
|
||||
Reference in New Issue
Block a user