Djangoのリクエストを非同期で処理

```
[Views.py]
import time
import json
import logging
import requests
import queue

from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response

import api.myutils as myutils
from books.models import Book

SLEEP_TIME = 10

class BookApiView(APIView):
    def get(self, request):
        resp = {'API': ''}
        return Response(resp, status = '200', content_type='application/json')

class BooksView(APIView):
    def get(self, request):
        resp_books = []
        resp = {}
        for book in Book.objects.all():
            resp_book = {'isbn': book.isbn, 'title': book.title, 'subtitle': book.subtitle, 'author': book.author}
            resp_books.append(resp_book)
        resp['Books'] = resp_books
        return Response(resp, status = '200', content_type='application/json')

    def post(self, request):
        try:
            data = json.loads(request.body)
            new_isbn = data["isbn"]
            new_title = data["title"]
            new_subtitle = data["subtitle"]
            new_author = data["author"]

        except KeyError:
            return Response(None, status = '400')

        if Book.objects.filter(isbn = new_isbn):
            return Response(None, status = '400')

        book = Book(isbn=new_isbn, title=new_title, subtitle=new_subtitle, author=new_author)
        if myutils.submit_task(new_isbn, BooksView.post_task, book):
            resp = {'id': new_isbn}
            return Response(resp, status = '200', content_type='application/json')
        else:
            resp = {'code': '409'}
            return Response(resp, status = '409', content_type='application/json')

    def post_task(book:Book):
        print('[post_task] start: ' + str(book))
        time.sleep(SLEEP_TIME)
        book.save()
        print('[post_task] end ' + str(book))
        return True

    def delete(self, request):
        Book.objects.all().delete()
        resp = {}
        return Response(resp, status = '200', content_type='application/json')

class BookView(APIView):
    def get(self, request, isbn):
        if not Book.objects.filter(isbn = isbn):
            return Response(None, status = '404')
        book = Book.objects.get(isbn = isbn)
        resp = {'isbn': book.isbn, 'title': book.title, 'subtitle': book.subtitle, 'author': book.author}
        return Response(resp, status = '200', content_type='application/json')

    def delete(self, request, isbn):
        if not Book.objects.filter(isbn = isbn):
            return Response(None, status = '404')
        Book.objects.get(isbn = isbn).delete()
        resp = {}
        return Response(resp, status = '200', content_type='application/json')
```

```
[myutils.py]
import json
import time
import datetime
import logging
import queue

from queue import Queue
from threading import Thread
from datetime import datetime

THREAD_MAX_SIZE = 2

task_queue = Queue(maxsize = THREAD_MAX_SIZE)
worker_threads = []
logger = None

class TaskEvent:
    def __init__(self, task_id, task, task_args):
        self.id = task_id
        self.task = task
        self.args = task_args

class WorkerThread(Thread):
    def __init__(self, tq:Queue, logger:logging.Logger):
        super().__init__()
        self.tq = tq
        self.logger = logger
        self.working = True

    def run(self):
        while self.working:
            task_event = self.tq.get()
            self.logger.info('task[' + task_event.id + '] start')
            result = task_event.task(task_event.args)
            self.logger.info('task[' + task_event.id + '] end: result = %s', result)

def initialize():
    formatter = '%(levelname)s : %(asctime)s : %(message)s'
    logging.basicConfig(level=logging.DEBUG, format = formatter)
    logger = logging.getLogger(__name__)

    for i in range(THREAD_MAX_SIZE):
        wt = WorkerThread(task_queue, logger)
        worker_threads.append(wt)
        wt.start()

def submit_task(task_id, task, task_args):
    try:
        task_event = TaskEvent(task_id, task, task_args)
        task_queue.put_nowait(task_event)
        return True
    except queue.Full:
        return False
```