Почему я должен создавать новый поток для обновления записи в базе данных? (Django Rest Framework)

Я использую Django Rest Framework для создания API.

Идея заключается в том, что пользователь загружает некоторые данные с помощью POST-запроса. Эти данные загружаются в базу данных. После загрузки создается новый поток Python, выполняющий некоторые операции над данными. После завершения операций результат записывается в исходную запись базы данных.

При таком подходе API остается доступным, а работа над операциями ведется в фоновом режиме. Пользователь может проверить состояние операций с помощью GET-запроса.

По какой-то причине при попытке обновить запись с результатами операции я получил следующую ошибку: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async

Это сбивало с толку, поскольку функция работы и обновления уже выполнялась с использованием потока.

Я не получал ошибки при замене операций простыми макетами результатов тестирования (строками). Даже при использовании time.sleep() в течение более длительного времени, чем требуется для выполнения реальных операций. Поэтому я подозреваю, что проблема как-то связана с операциями, которые я запускаю, хотя они никак не взаимодействуют с Django.

Я решил проблему, создав новые потоки специально для сохранения обновленных данных в базе данных. Но я все еще задаюсь вопросом: Зачем это нужно?

@api_view(['POST'])
def create_job(request):
    serializer = JobsSerializer(data=request.data)
    if serializer.is_valid():
        job = serializer.save()
        job_thread = threading.Thread(target=trigger_operation, args=(job,)).start()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


def trigger_operation(db_record):
    db_record.status = Jobs.Status.WORKING
    threading.Thread(target=db_record.save, args=()).start()

    try:
        results = actual_operation(db_record.url)
        status = Jobs.Status.DONE
    except Exception as e:
        results = e
        status = Jobs.Status.FAILED
    finally:
        db_record.status = status
        db_record.results = results
        threading.Thread(target=db_record.save, args=()).start()
Вернуться на верх