Wie man Daten von einer CherryPy BackgroundTask zurückgibt, die so schnell wie möglich läuft

Ich baue einen Web-Service für die iterative Batch-Verarbeitung von Daten mit CherryPy. Der ideale Workflow ist wie folgt:

  1. Benutzer POST-Daten an den Dienst für die Verarbeitung
  2. Wenn der Bearbeitungsauftrag frei ist, sammelt er die in der Warteschlange befindlichen Daten und startet eine weitere Iteration
  3. Während der Auftrag verarbeitet wird, verteilen die Benutzer mehr Daten an die Warteschlange für die nächste Iteration
  4. Sobald die aktuelle Iteration beendet ist, werden die Ergebnisse zurückgegeben, so dass Benutzer sie mit der gleichen API erhalten können.
  5. Der Job startet mit der nächsten Charge der in der Warteschlange befindlichen Daten.

Die zentrale Betrachtung hierbei ist, dass die Verarbeitung so schnell wie möglich mit jeder Iteration ablaufen sollte, sobald die vorherige beendet ist, unabhängig von der Datenmenge in der Warteschlange. Es gibt keine Obergrenze, wie lange jede Iteration so nehmen kann, dass ich keinen festen Zeitplan dafür erstellen kann.

Es gibt ein paar Beispiele für die Verwendung von BackgroundTask ( wie diese ), aber ich habe noch eine zu finden, die sich mit der Rücksendung von Daten befasst, oder eine, die mit Aufgaben arbeitet, die so schnell wie möglich laufen, im Gegensatz zu einem festen Zeitplan.

Ich bin nicht mit der BackgroundTask Lösung verheiratet, also wenn jemand eine Alternative anbieten könnte, wäre ich mehr als glücklich. Es fühlt sich an wie es eine Lösung innerhalb des Rahmens aber gibt.

  • Abbrechende Threading.Timer in Python
  • Parallelisierung dieser verschachtelten für Schleife in Python
  • Mehrere scipy.integrate.ode-Instanzen
  • Wie kann ich mehrere Clients auf einem TCP Python Chat Server haben?
  • Timeout bei einem Funktionsaufruf
  • Threading und Information übergeben - wie zu
  • Sharing a: memory: datenbank zwischen verschiedenen threads in python mit sqlite3 package
  • Multi-Threading in Selen-Python
  • One Solution collect form web for “Wie man Daten von einer CherryPy BackgroundTask zurückgibt, die so schnell wie möglich läuft”

    Führen Sie keine Hintergrundaufgabe mit der BackgroundTask Lösung aus, da es in einem Thread läuft und aufgrund der GIL wird cherrypy nicht in der Lage sein, neue Anfragen zu beantworten. Verwenden Sie eine Warteschlangenlösung, die Ihre Hintergrundaufgaben in einem anderen Prozess ausführt , wie Celery oder RQ .

    Ich werde im Detail ein Beispiel mit RQ entwickeln. RQ verwendet Redis als Message Broker, also müssen Sie zunächst Redis installieren und starten.

    Dann erstellen Sie ein Modul ( mytask in meinem Beispiel) mit der langen Zeit laufen Hintergrund Methoden:

     import time def long_running_task(value): time.sleep(15) return len(value) 

    Starten Sie eine (oder mehr als eine, wenn Sie Aufgaben parallel ausführen möchten) RQ Arbeiter, es ist wichtig, dass die Python, die Ihre Arbeiter läuft, Zugriff auf Ihr mytask Modul hat (Exportieren Sie den PYTHONPATH, bevor Sie den Arbeiter laufen lassen, wenn Ihr Modul nicht bereits vorhanden ist der Weg):

     # rq worker 

    Oben hast du eine sehr einfache cherrypy webapp, die zeigt, wie man die RQ-Warteschlange benutzt:

     import cherrypy from redis import Redis from rq import Queue from mytask import long_running_task class BackgroundTasksWeb(object): def __init__(self): self.queue = Queue(connection=Redis()) self.jobs = [] @cherrypy.expose def index(self): html = ['<html>', '<body>'] html += ['<form action="job">', '<input name="q" type="text" />', '<input type="submit" />', "</form>"] html += ['<iframe width="100%" src="/results" />'] html += ['</body>', '</html>'] return '\n'.join(html) @cherrypy.expose def results(self): html = ['<html>', '<head>', '<meta http-equiv="refresh" content="2" >', '</head>', '<body>'] html += ['<ul>'] html += ['<li>job:{} status:{} result:{} input:{}</li>'.format(j.get_id(), j.get_status(), j.result, j.args[0]) for j in self.jobs] html += ['</ul>'] html += ['</body>', '</html>'] return '\n'.join(html) @cherrypy.expose def job(self, q): job = self.queue.enqueue(long_running_task, q) self.jobs.append(job) raise cherrypy.HTTPRedirect("/") cherrypy.quickstart(BackgroundTasksWeb()) 

    In einer Produktion webapp würde ich jinja2 Template Engine verwenden, um die html zu generieren, und wahrscheinlich Webseiten, um den Jobstatus im Webbrowser zu aktualisieren.

    Python ist die beste Programmiersprache der Welt.