When developing APIs using Django REST Framework (DRF), optimizing performance is a key consideration, especially when handling tasks that can slow down response times. One effective way to improve the performance of an API is by using threading. In this blog, we will discuss how to use threading to perform background tasks such as sending emails without blocking the main thread, making the API more responsive.
When you have tasks that take a long time to execute—like sending emails, making external API calls, or processing data—it can lead to a significant delay in the API's response time. Threading allows you to run these tasks in parallel to the main thread, so the API response can be sent immediately while the longer tasks continue to run in the background.
Imagine an API where users can create new posts. When a new post is created, we want to notify all users by sending them an email. Since sending emails can take a while, especially if the recipient list is large, it is ideal to perform this task in the background to avoid keeping the API request open until all emails are sent. We can achieve this by creating a dedicated threading class.
HandleNotification
Class for ThreadingHandleNotification
Class for ThreadingWe start by creating a HandleNotification
class that inherits from threading.Thread
. This class will handle the task of sending notification emails in the background.
# views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from django.core.mail import send_mail
from django.conf import settings
from .models import Post
from .serializers import PostSerializer
from django.contrib.auth.models import User
import threading
class HandleNotification(threading.Thread):
"""
Threading class to handle sending notification emails in the background.
"""
def __init__(self, post):
super().__init__() # Initialize the parent class
self.post = post
def run(self):
"""
The method that runs when the thread starts.
Sends notification emails to all users.
"""
# Fetch all users' emails (assuming a User model with an email field)
emails = [user.email for user in User.objects.all() if user.email]
# Email sending logic
send_mail(
subject=f'New Post Created: {self.post.title}',
message=f'Check out the new post: {self.post.content}',
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=emails,
fail_silently=False,
)
In this implementation:
__init__
method initializes the class with the post
object.run
method contains the logic to send emails to all users. This method will be called when the thread starts.Next, we create an APIView that handles the creation of a new post. Once a post is successfully created, we start a new thread using the HandleNotification
class to send emails.
# views.py
class PostCreateAPIView(APIView):
"""
API View to create a new post and send email notifications to users.
"""
def post(self, request, *args, **kwargs):
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
# Save the new post
post = serializer.save()
# Start a new thread to send emails using the HandleNotification class
notification_thread = HandleNotification(post)
notification_thread.start()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
In this APIView:
post
method is used to handle POST requests for creating a new post.HandleNotification
, passing the newly created post as an argument.