Files
tabdeal-job-queue/backend/jobs/views.py

97 lines
3.6 KiB
Python

from django.db import connection
from rest_framework import generics, status
from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.response import Response
from rest_framework.views import APIView
from jobs.models import Job, JobEvent
from jobs.serializers import JobCreateSerializer, JobEventSerializer, JobSerializer
from jobs.services import create_job, job_stats, retry_failed_job
class HealthAPIView(APIView):
def get(self, request):
try:
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
cursor.fetchone()
except Exception as exc:
return Response(
{"ok": False, "database": "error", "detail": str(exc)},
status=status.HTTP_503_SERVICE_UNAVAILABLE,
)
return Response({"ok": True, "database": "ok"})
class JobListCreateAPIView(APIView):
def get(self, request):
queryset = Job.objects.order_by("-created_at")
status_filter = request.query_params.get("status")
if status_filter:
queryset = queryset.filter(status=status_filter)
return Response(JobSerializer(queryset, many=True).data)
def post(self, request):
serializer = JobCreateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
result = create_job(
job_type=serializer.validated_data["type"],
payload=serializer.validated_data.get("payload") or {},
priority=serializer.validated_data.get("priority", 50),
available_at=serializer.validated_data.get("available_at"),
max_attempts=serializer.validated_data.get("max_attempts"),
idempotency_key=serializer.validated_data.get("idempotency_key"),
)
return Response(
JobSerializer(result.job).data,
status=status.HTTP_201_CREATED if result.created else status.HTTP_200_OK,
)
class JobDetailAPIView(generics.RetrieveAPIView):
queryset = Job.objects.all()
serializer_class = JobSerializer
class JobEventsAPIView(APIView):
def get(self, request, pk):
if not Job.objects.filter(id=pk).exists():
raise NotFound("Job not found.")
events = JobEvent.objects.filter(job_id=pk).order_by("id")
return Response(JobEventSerializer(events, many=True).data)
class GlobalJobEventsAPIView(APIView):
def get(self, request):
queryset = JobEvent.objects.order_by("id")
after_id = request.query_params.get("after_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)
class JobStatsAPIView(APIView):
def get(self, request):
return Response(job_stats())
class RetryJobAPIView(APIView):
def post(self, request, pk):
try:
job = retry_failed_job(pk)
except Job.DoesNotExist as exc:
raise NotFound("Job not found.") from exc
except ValueError as exc:
raise ValidationError({"detail": str(exc)}) from exc
return Response(JobSerializer(job).data)