2016-05-18 18 views
1

Ich habe eine web2py-Anwendung, die im Grunde als Browser-Schnittstelle für ein Python-Skript dient. Dieses Skript kehrt normalerweise ziemlich schnell zurück, kann aber gelegentlich lange dauern. Ich möchte eine Möglichkeit für den Benutzer bereitstellen, die Ausführung des Skripts zu stoppen, wenn es zu lange dauert.Stoppt eine lang andauernde Aktion in web2py mit Multiprocessing

ich derzeit Aufruf der Funktion wie folgt aus:

def myView(): # this function is called from ajax 
    session.model = myFunc() # myFunc is from a module which i have complete control over 
    return dict(model=session.model) 

myFunc, wenn sie mit bestimmten Optionen genannt, verwendet Multiprozessing aber noch endet eine lange Zeit. Ich brauche einen Weg, um die Funktion zu beenden, oder zumindest die Kinder des Threads.

Das erste, was ich versuchte, war myFunc in einem neuen Prozess laufen zu lassen, und mein eigenes einfaches Ereignissystem rollt sie zu töten:

# in the controller 
def myView(): 
    p_conn, c_conn = multiprocessing.Pipe() 
    events = multiprocessing.Manager().dict() 
    proc = multiprocessing.Process(target=_fit, args=(options, events c_conn)) 
    proc.start() 
    sleep(0.01) 
    session.events = events 
    proc.join() 
    session.model = p_conn.recv() 
    return dict(model=session.model) 

def _fit(options, events pipe): 
    pipe.send(fitting.logistic_fit(options=options, events=events)) 
    pipe.close() 

def stop(): 
    try: 
     session.events['kill']() 
    except SystemExit: 
     pass # because it raises that error intentionally 
    return dict() 

# in the module 
def kill(): 
    print multiprocessing.active_children() 
    for p in multiprocessing.active_children(): 
     p.terminate() 
    raise SystemExit 

def myFunc(options, events): 
    events['kill'] = kill 

Ich lief in ein paar großen Probleme mit diesem.

  1. Die Sitzung in stop() war nicht immer das gleiche wie die Sitzung in myView(), so session.events Keine war.
  2. Selbst wenn die Sitzung die gleiche war, tötete kill() nicht ordnungsgemäß die Kinder.
  3. Die lang laufende Funktion würde den web2py-Thread hängen, so dass stop() nicht einmal verarbeitet wurde, bis die Funktion beendet wurde.

Ich hielt Aufruf nicht join() und AJAX mit dem Ergebnis der Funktion zu einem späteren Zeitpunkt zu holen, aber ich war für die spätere Verwendung in session das Prozessobjekt speichern nicht in der Lage. Das Rohr schien in der Lage zu sein, gebeizt zu werden, aber dann hatte ich das Problem, von einer anderen Ansicht nicht auf die gleiche Sitzung zugreifen zu können.

Wie kann ich diese Funktion implementieren?

Antwort

1

Für lange laufende Aufgaben, sind Sie besser in der Warteschlange sie über die eingebaute scheduler. Wenn Sie dem Benutzer erlauben möchten, eine Aufgabe, die zu lange dauert, manuell zu stoppen, können Sie die Methode scheduler.stop_task(ref) verwenden (ref ist die Aufgabe id oder uuid). Wenn Sie eine Aufgabe in eine Warteschlange stellen, können Sie alternativ eine Zeitüberschreitung festlegen, sodass sie automatisch beendet wird, wenn sie nicht innerhalb der Zeitüberschreitung abgeschlossen wurde.

Sie können eine einfache Ajax-Abfrage durchführen, um den Client zu benachrichtigen, wenn die Aufgabe abgeschlossen ist (oder etwas komplizierteres mit Websockets oder SSE implementieren).

+0

Können Sie bitte auf Ihre Antwort erweitern? Einige spezifische Dinge, die es wert wären, beantwortet zu werden: Startet der Scheduler die Aufgabe sofort, von einem Skript? Wie bekomme ich das Ergebnis der Aufgabe? Wie kann man die Aufgabe erzwingen? So beantwortet es die Frage nicht vollständig. – Scimonster

+0

Ich habe die Antwort aktualisiert, um Ihre letzte Frage zu beantworten. Ihre ersten beiden Fragen werden in der verknüpften Dokumentation behandelt. Da sie allgemeine Scheduler-Funktionalität beinhalten und nicht Teil Ihrer ursprünglichen Frage sind, werde ich die Antwort nicht aktualisieren, aber ich werde kurz erwähnen, dass neue Aufgaben standardmäßig sofort in die Warteschlange gestellt werden (und Sie können einen Mitarbeiter zwingen, die Warteschlange sofort zu überprüfen 'sofort = Wahr '), und die' scheduler.task_status() 'Methode wird verwendet, um Ergebnisse abzurufen. – Anthony