2010-05-11 15 views
10

Ich habe eine asp.net (mvc) Website. Als Teil der Funktionen muss ich einige lang andauernde Operationen unterstützen, zum Beispiel:Lange laufende Operationen (Threads) in einer Web (asp.net) Umgebung

Initiiert vom Benutzer: Benutzer kann (xml) Datei auf den Server hochladen. Auf dem Server muss ich eine Datei extrahieren, etwas manipulieren (in die Datenbank einfügen) usw. ... Dies kann von einer Minute bis zu zehn Minuten dauern (oder sogar mehr - hängt von der Dateigröße ab). Natürlich möchte ich die Anfrage nicht blockieren, wenn der Import läuft, aber ich möchte den Benutzer auf eine Fortschrittsseite umleiten, wo er die Möglichkeit hat, den Status oder Fehler zu sehen oder sogar den Import abzubrechen.

Diese Operation wird nicht häufig verwendet, aber es kann vorkommen, dass zwei Benutzer gleichzeitig versuchen, die Daten zu importieren. Es wäre schön, die Importe parallel laufen zu lassen. Zu Beginn dachte ich daran, einen neuen Thread in der iis (Controller-Aktion) zu erstellen und den Import in einem neuen Thread auszuführen. Aber ich bin mir nicht sicher, ob das eine gute Idee ist (um Arbeitsfäden auf einem Webserver zu erstellen). Sollte ich Windows-Dienste oder einen anderen Ansatz verwenden?

Initiiert vom System: - Ich muss regelmäßig Lucene Index mit den neuen Daten aktualisieren. - Ich werde in Zukunft Massen-E-Mails senden müssen.

Sollte ich dies als einen Job auf der Website implementieren und den Job über Quartz.net ausführen oder sollte ich auch einen Windows-Dienst oder etwas erstellen?

Welche Best Practices gelten für die Ausführung von Site-Jobs?

Danke!

+0

Betrachten Sie einige dieser Antworten zu einer verwandten Frage http://StackOverflow.com/a/41734936/56145 –

Antwort

6

Ich würde Stand-Alone-Windows-Dienst für lange laufende Aufgaben implementieren. Die Webanwendung delegiert über den Warteschlangenansatz lang laufende Aufgaben an diesen Dienst. Es liegt an Ihnen, wie Sie die Aufgabenwarteschlange organisieren. Die Aufgabe in der Warteschlange hat Priorität, maximale Ausführungszeit oder nicht. Die Warteschlange kann als gewöhnliche Tabelle (n) in DBMS implementiert werden, die Job-Ausführungsstatus-Info-Eigenschaften enthält (ziemlich direkter Ansatz).

So gängiges Szenario wird möglicherweise die folgende aussehen:

  • Client sendet alle erforderlichen Informationen auf dem Web-Server

  • Web-Server delegiert Aufgabe Service und benachrichtigt Client - Aufgabe wurde erfolgreich Warteschlange (Aufgaben-ID wird auch an den Client gesendet)

  • Der externe Dienst startet die Verarbeitung der Aufgabe, updating progress informatio n.

  • Client startet abfragen Webserver mit kurze Ausführungsanforderungen über Job (mit ID früher erhalten) Status und Fortschritt.

Sie können verschiedene Technologien wählen (Windows Service + DB/WCF-Dienst) und verschiedene Kommunikationsansätze (Polling, Stoßen, Rückrufe), aber ich rate lang laufende Aufgaben an externe Dienstleister zu delegieren (nicht ausführen, sie innerhalb web App).

Die Ausführung von Aufgaben mit langer Laufzeit führt zu einem Thread-pro-Anfrage-Modell (in Multithread-Programmierbegriffen). Dieses Modell weist eine geringe Skalierbarkeit und maximale Threadanzahl für Threads auf. Es ist jedoch nicht dein Fall :)

+0

Ich habe früher schwere Konvertierungen, Berichte Generationen, Datengenerationen in so. Dies ist die einzig logische Wahl. –

4

Meiner Meinung nach sollten lange laufende Aufgaben im Allgemeinen immer an nicht UI-basierte Operationen delegiert werden. Ich würde vielleicht einen WF- oder Window-Service vorschlagen.

1

Ich habe erfolgreich ein ähnliches Szenario mit jQuery implementiert. grundsätzlich benutze ich die beforeSend: funktion, um die 'bitte warten' type seite anzuzeigen. hier ist der Grund-Code im Spiel (altso ich nicht tun, könnten Sie auch die AsyncController Basisklasse verwenden, um die Aktion async zu machen):

<script type="text/javascript"> 
    $(document).ready(function() { 
     $('#create').bind('click', function() { 
      saveFundProperty(); 
     }); 
    }); 

    // main functions 
    function saveFundProperty() { 
     var url = '<%= Url.Action("Create", "FundProperty") %>'; 
     var params = { fundId: $("#FundID").val(), propertyId: $("#PropertyID").val() }; 
     SendAjax(url, params, beforeQuery, saveFundPropertyResponse); 
    } 

    function beforeQuery() { 
     var url = '<%= Url.Action("Wait", "FundProperty") %>'; 
     $("#statusMsg").load(url); 
    } 

    function saveFundPropertyResponse(data) { 
     if (data.length != 0) { 
      if (data.indexOf("ERROR:") >= 0) { 
       $("#statusMsg").html(data).css('backgroundColor','#eeaa00'); 
      } 
      else { 
       $("#statusMsg").html(data); 
      } 
     } 
    } 
</script> 

Hoffnung, das hilft.

Die SendAjax Methode ist eine reine Wrapper-Funktion, um die Dinge etwas konsistenter zu machen. hier ist es in vollem Umfang:

[bearbeiten] - nicht sicher, was passiert mit der SendAjax Formatierung. hoffe, es ist einfach zu kopieren/einfügen ...

Verwandte Themen