2016-04-15 8 views
2

Ich erstelle einen Web-Service für die iterative Stapelverarbeitung von Daten mit CherryPy. Der ideale Workflow ist wie folgt:So geben Sie Daten von einer CherryPy BackgroundTask zurück, die so schnell wie möglich ausgeführt wird

  1. Benutzer POST-Daten an den Dienst für die Verarbeitung
  2. Wenn die Verarbeitung Job frei ist, sammelt er die Daten in der Warteschlange und startet eine weitere Iteration
  3. Während die Auftragsbearbeitung ist, Benutzer Weitere Daten werden an die Warteschlange für die nächste Iteration gesendet.
  4. Sobald die aktuelle Iteration abgeschlossen ist, werden die Ergebnisse zurückgegeben, sodass Benutzer sie mit der gleichen API abrufen können.
  5. Der Job beginnt erneut mit dem nächsten Stapel von Daten in der Warteschlange.

Die wichtige Überlegung dabei ist, dass die Verarbeitung so schnell wie möglich ausgeführt werden soll, sobald die vorhergehenden beendet ist, unabhängig von der Datenmenge in der Warteschlange bei jeder Iteration zu starten. Es gibt keine obere Grenze für die Dauer der einzelnen Iterationen, daher kann ich keinen festen Zeitplan für die Ausführung erstellen.

Es gibt einige Beispiele für die Verwendung BackgroundTask (like this one), aber ich habe noch zu finden, die mit der Rückkehr Daten umgehen, oder eine, die so schnell wie möglich behandelt mit Aufgaben laufen im Gegensatz zu einem festen Zeitplan.

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

Antwort

2

Sie keine Hintergrundaufgabe mit der BackgroundTask Lösung ausgeführt werden, da es in einem Thread und aufgrund der GIL, cherrypy nicht in der Lage ausgeführt wird neue Anfragen zu beantworten. Verwenden Sie eine Warteschlangenlösung, die Ihre Hintergrundaufgaben in einem anderen Prozess ausführt, z. B. Celery oder RQ.

Ich werde im Detail ein Beispiel mit RQ entwickeln. RQ verwendet Redis als Nachrichtenbroker, daher müssen Sie zuerst Redis installieren und starten.

Erstellen Sie dann ein Modul (mytask in meinem Beispiel) mit der langen Zeit, Methoden Hintergrund ausgeführt wird:

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

Starten einer RQ Arbeiter (oder mehr als ein, wenn Sie Aufgaben parallel ausgeführt werden soll), ist es wichtig, dass die python, die Ihre Mitarbeiter hat Zugriff auf Ihre mytask Modul ausgeführt wird (die PYTHONPATH exportieren, bevor die Arbeiter ausgeführt wird, wenn Ihr Modul nicht bereits auf dem Weg ist):

# rq worker 

Above Sie eine sehr einfache cherrypy Webapp haben das zeigt, wie die RQ-Warteschlange verwenden:

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 Produktions Webapp würde ich Template-Engine verwenden jinja2 die HTML zu erzeugen, und höchstwahrscheinlich WebSockets den Jobstatus im Web-Browser zu aktualisieren.

+0

Große Antwort, danke! Am Ende habe ich es mit einer ähnlichen Architektur gehackt, aber nicht annähernd so sauber wie du es getan hast. Ich habe weder von Sellerie noch von RQ gehört, aber ich werde in Zukunft nach ihnen suchen. – Mourndark