Muster für Anfragen mit langen Antwortzeiten?

7

Wir unterhalten derzeit einen selbst entwickelten Python- "Webserver", auf dem das Generieren der Antwort für einige Anfragen sehr lange dauern kann, hauptsächlich aufgrund umfangreicher Berechnungen. Bei diesen Anfragen handelt es sich im Grunde genommen um Posts mit sehr langen Zeitüberschreitungen (denken Sie an Minuten bis Dutzende von Minuten).

Ein Problem dieser Architektur besteht darin, dass manchmal eine solche Anforderung abgebrochen werden muss - z. B. hat der Benutzer beim Konfigurieren der Anforderung einen Fehler festgestellt. Derzeit ist die Stornierung eine weitere Anfrage, die die langfristige Anfrage storniert - aber es gibt viele Lücken, z. B. was passiert, wenn der Kunde die Website einfach schließt?

Gegenwärtig planen wir, die hausgemachte Abscheulichkeit eines Webservers einzustellen und auf etwas Sinnvolles umzusteigen - z. B. Flask, der mit wfastcgi in einem IIS ausgeführt wird. Aus politischen Gründen ist IIS so eingestellt, dass der Wechsel zu etwas wie Gunicorn aus dem Fenster ist.

Alle Entwicklungen sind ins Stocken geraten, weil niemand eine Idee hat, wie die von (w) fastcgi ausgeführten Prozesse beendet werden können - diese Sorge ist einfach nicht Teil der fastcgi-Spezifikation.

Mein Gefühl ist, dass ein Versuch, etwas zu erstellen, das dies beinhaltet, ein Fehler ist. Ich würde eine Lösung vorziehen, bei der der Server solche rechenintensiven Aufgaben einfach einem Hintergrundserver (Flasche + Sellerie?) Und den Front-End-Umfragen dafür entlädt.

Leider war die alte Lösung so lange vorhanden, dass einige Entwickler das Verhalten um jeden Preis beibehalten möchten.

Da ich kein Webserver-Typ bin, möchte ich einige Tipps / Muster, wie vernünftige Lösungen für ein solches Problem aussehen könnten.

Christian Sauer
quelle

Antworten:

8

Was Sie vorschlagen, ist ganz richtig.

Es sollte asynchron sein.

Sie können eine Anfrage stellen und die Anfrage gibt Ihnen eine eindeutige ID. Es wird ein Fertig auf dieser eindeutigen ID in einem Geschäft veröffentlicht, in dem Sie abfragen können.

Wenn Sie eine Anfrage stornieren müssen, sollte eine Stornierungsanfrage mit derselben ID veröffentlicht werden.

Auch im Back-End, in dem diese Berechnungen ausgeführt werden, z. B. in einer Ausführungsschnittstelle eines Threads (Java-Stil), können Sie alle paar Sekunden überprüfen, ob der Vorgang abgebrochen wurde, indem Sie überprüfen, ob ein Abbruchbeitrag angefordert wurde. Wenn dies der Fall ist, muss der Thread beendet werden. Dies ist ein sauberer Ausgang. Sie können auch einen Interrupt für den Thread verwenden.

Learner_101
quelle
IMHO ist diese Lösung diejenige, die am besten zu dem "zustandslosen" Ansatz passt, der so gut zu HTTP passt - Sie trennen den Vorgang der Berechnung von der Anforderungs- / Antwortkommunikation. In diesem Muster wird die Anforderungs- / Antwortkommunikation zu einem Gespräch wie diesem: 'Bitte fangen Sie an ... okay, ich werde ... wie geht es Ihnen? .. arbeitet noch .. bitte stornieren .. okay ich storniere .. wie geht es dir? .. Berechnung wurde abgebrochen .. bitte anfangen ... (wartet) .. wie geht es dir? .. Berechnung hier abgeschlossen sind die Ergebnisse. '.
Robert
2

Ich schlage vor, Sie schauen in wsgi und verwenden Multithreading . Sie können jede Anforderung in einem Thread verwalten und Zeitüberschreitungen im Thread implementieren. Sie sollten auch in der Lage sein, die Threads zu verwalten und Anforderungen einfacher abzubrechen.

Tereus Scott
quelle
1

Das Problem, mit dem Sie derzeit bei einem einfachen HTTP-Beitrag konfrontiert sind, kann in diesem Protokoll einfach nicht gelöst werden. HTTP arbeitet asynchron in strengen Clients / Servern, sodass keine serverseitige Benachrichtigung und kein nativer Abbruch erfolgt. Außerdem haben Sie das Problem, dass Antworten aufgrund von Zeitüberschreitungen im Internet verloren gehen. Ich werde einen anderen und modernen Ansatz vorschlagen. Haftungsausschluss: etwas weniger als 90% Browserunterstützung

Ich würde vorschlagen, dass Sie den Informationsfluss umkehren und Websockets verwenden. Was Sie tun müssen , wenn eine Aufgabe erledigt ist Ihr Benutzer zu benachrichtigen , und drücken Sie eine Benachrichtigung vom Server zum Client.

Wenn eine Aufgabe veröffentlicht wird oder genauer gesagt, als Ersatz für den Beitrag, öffnen Sie einen Websocket (verwenden Sie die von Ihnen gewünschte Servertechnologie, Tornado, Gevent, Python-Websocket usw.). Ordnen Sie den Task-Thread dem offenen Ereignis "Server-Websocket" zu. Wenn der Client beendet wird, sendet der Client ein Abschlussereignis an Ihren Websocket-Handler, damit Sie den damit verbundenen Thread beenden können. Wenn Ihre Aufgabe normal endet, kann der Server die Daten an den Client senden und den Websocket schließen. Außerdem muss der Server alle 30 Sekunden einen Ping-Befehl senden, da Websockets geschlossen werden, wenn sie länger als eine Minute inaktiv sind.

Wenn Sie dies anwenden, ist dies schneller und sauberer als eine clientseitige Abfrage, während Lückenprobleme gelöst werden, da Sie über einen echten bidirektionalen Kanal verfügen. Beachten Sie, dass Sie zusätzliche Dienste über das Aufgabenschema implementieren können, z. B. Sitzungen, Fortschritts-Pings usw.

Arthur Havlicek
quelle
0

Wenn Ihre Aufgabe so viel Zeit benötigt, tun Sie dies nicht auf diese Anfrage hin. Stellen Sie es in die Warteschlange und machen Sie einen anderen Prozess, der die Arbeit erledigt.

Nachdem die Arbeit erledigt ist, senden Sie einfach eine Benachrichtigung an den Benutzer, dass "Operation x" abgeschlossen ist. Zeigen Sie in der Zwischenzeit die Meldung "Ihre Arbeit wird in ca. x Minuten erledigt sein" an.

Djuro
quelle