I implemented an endpoint to run a background task. When you hit the post
the endpoint returns the id of the job. Then you can hit the get
endpoint with the job task id and you get back the result or in progress
if the job is still running.
I didn't use celery
to accomplish this task, but django-q that I found easier than celery and moreover django-q uses all the batteries django has already. Here an example of API View I implemented with django-q.
from django.urls import reverse
from django_q.models import Task, OrmQ
from django_q.tasks import async, result
from rest_framework.exceptions import NotFound
from rest_framework.response import Response
from rest_framework.views import APIView
def the_function_to_run():
# do something here
pass
class YourTaskApiView(APIView):
def get(self):
# you mustr construct the get url to take the id
task_id = self.kwargs.get('task_id')
try:
task = Task.objects.get(id=task_id)
except Task.DoesNotExist:
task = None
# here the task is on processing
if task:
return Response({
'id': task_id,
'result': result(task_id),
'started': task.started,
'stopped': task.stopped,
'status': 'DONE' if task.stopped else 'RUNNING',
'success': task.success,
})
else:
# here you find the task in the query (not even processed, but waiting for the cluster to process it)
for q in OrmQ.objects.all():
if q.task_id() == task_id:
task = q.task()
return Response({
'id': task['id'],
'started': task['started'],
'status': 'WAITING', # or ON QUEUE
'stopped': None,
'success': None,
})
return NotFound()
def post(self, request):
# run the task as async
task_id = async(the_function_to_run)
# create the reverse for the get so the client already has the link to query for
# the task status
link = reverse('yourapp:yournamespace:yourview', kwargs={'task_id': task_id}, request=request)
return Response(data={'task_id': task_id, 'link': link})