Die Idee ist, dass der Benutzer einige Daten mithilfe einer POST-Anfrage hochlädt. Diese Daten werden in eine Datenbank hochgeladen. Nach dem Hochladen wird ein neuer Python-Thread erstellt, der einige Vorgänge für die Daten ausführt. Wenn die Vorgänge dann abgeschlossen sind, wird das Ergebnis in den ursprünglichen Datenbankdatensatz geschrieben.
Mit diesem Ansatz bleibt die API zugänglich, während gleichzeitig die Vorgänge im Hintergrund bearbeitet werden. Der Benutzer kann den Vorgangsstatus mithilfe einer GET-Anfrage überprüfen.
Aus irgendeinem Grund wurde beim Versuch, den Datensatz mit den Vorgangsergebnissen zu aktualisieren, die folgende Fehlermeldung angezeigt:
Code: Select all
SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async
Ich würde den Fehler nicht erhalten, wenn Ersetzen der Operationen durch einige einfache Modelltestergebnisse (Strings). Auch nicht, wenn time.sleep() für einen längeren Zeitraum verwendet wird, als die tatsächlichen Vorgänge dauern würden. Daher vermute ich, dass das Problem etwas mit den von mir ausgeführten Vorgängen zu tun hat, auch wenn diese überhaupt nicht mit Django interagieren.
Die fehlerhaften Zeilen werden auskommentiert und durch funktionierenden Code ersetzt. Ich habe das Problem behoben, indem ich neue Threads speziell zum Speichern der aktualisierten Daten in der Datenbank erstellt habe. Aber ich frage mich immer noch: Warum ist das notwendig?
Code: Select all
@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() # db_record.save()
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() # db_record.save()