2010-10-06 29 views
5

Die ASP.NET-Laufzeit ist für kurze Arbeitsauslastungen vorgesehen, die parallel ausgeführt werden können. Ich muss in der Lage sein, periodische Ereignisse und Hintergrundaufgaben zu planen, die möglicherweise für viel längere Zeit ausgeführt werden.Entwerfen einer asynchronen Taskbibliothek für ASP.NET

die oben angegeben Ich habe folgende Probleme zu bewältigen:

  • Die AppDomain kann aufgrund von Änderungen shutdown (Web.config, sind, App_Code, etc.)
  • IIS recycelt die AppPool auf einem regelmäßig (täglich)
  • IIS selbst neu starten könnte, oder was das betrifft könnte der Server

abstürzen ich bin nicht davon überzeugt, dass dieser Code in ASP.NET ausgeführt wird, nicht das richtige zu tun, becuase es würde ein einfacheres Programmiermodell ermöglichen. Dies erfordert jedoch, dass ein externer Dienst regelmäßig Anfragen an die App sendet, damit die Anwendung ausgeführt wird und alle Hintergrundaufgaben mit äußerster Sorgfalt programmiert werden. Sie müssen im Falle eines unerwarteten Fehlers ihre Arbeit unterbrechen und fortsetzen können.

Meine heutige Linie des Denkens geht ungefähr so:

Wenn alle Jobs in der Datenbank registriert sind, sollte es möglich sein, die Datenbank als Buchhaltung Mechanismus zu verwenden. Im Falle eines Fehlers würde die Datenbank alle Zustände enthalten, die notwendig sind, um die Operation bei der nächsten gegebenen Gelegenheit fortzusetzen.

Ich würde wirklich einige Rückmeldungen/Ratschläge in dieser Angelegenheit applaudieren. Ich habe darüber nachgedacht, einen Windows-Dienst zu betreiben und auch eine RPC-Lösung zu verwenden, aber das hat nicht den gleichen Reiz für mich. Stattdessen hätte ich viele Probleme bei der Bereitstellung und die Synchronisierung von Aufgaben und Code durch mehrere Anwendungen. Aufgrund meiner geschäftlichen Bedürfnisse ist dies weniger als optimistisch.

Antwort

4

Dies ist ein Schuss in die Dunkelheit, da ich nicht weiß, welche Datenbank Sie verwenden, aber ich würde Ihnen empfehlen, dialog timers und activation zu betrachten. Angenommen, dass die meisten der Jobs haben einige Datenmanipulation zu tun, und ist wahrscheinlich, dass nur Datenmanipulation, Aktivierung und Timer geben eine äußerst zuverlässige Job Scheduling-Lösung, vollständig in die Datenbank eingebettet (Nr Notwendigkeit für einen externen Prozess/Service, keine Abhängigkeiten außerhalb der Datenbank Grenzen wie msdb), und ist eine Lösung, die gewährleistet, dass geplante Aufträge können Neustarts, Failover-Ereignisse und sogar Wiederherstellungen Disaster Recovery überleben. Einfach ausgedrückt: Sobald ein Job geplant ist, wird er ausgeführt, selbst wenn die Datenbank eine Woche später auf einem anderen Computer wiederhergestellt wird.

Werfen Sie einen Blick auf Asynchronous procedure execution für ein verwandtes Beispiel.

Und wenn das zu radikal ist, sehen Sie sich zumindest Using Tables as Queues an, da das Speichern der geplanten Elemente in der Datenbank oft unter den Fall "ausstehende Warteschlange" fällt.

+0

+1 für den Link zum Artikel über die asynchrone Prozedurausführung. –

+0

Das ist genial, leider können nicht alle Hintergrundaufgaben in nur T-SQL geschrieben werden, viele von ihnen könnten das wahrscheinlich, aber im Moment haben wir nur eingeschränkte Debugging-Unterstützung für T-SQL und Dinge, die in C# sein müssen. Code, wie das Senden von E-Mails. Auch einige dieser Transformationen, die wir machen, sehen in SQL wirklich peinlich aus und sind für uns oft einfacher, C# -Code zu verwenden. Über Tabellen als Warteschlangen habe ich in der Vergangenheit etwas Ähnliches gemacht, habe diese Variationen aber noch nicht gesehen, danke für die Links. –

+0

Aktivierung kann auch CLR-Prozeduren starten, und es gibt auch einen externen Aktivator, der normale Prozesse (.exe) starten kann: http://blogs.msdn.com/b/sql_service_broker/archive/2008/11/21/announcing- service-broker-external-activator.aspx –

2

Ich empfehle, dass Sie sich Quartz.Net anschauen. Es ist Open Source und es wird Ihnen einige Ideen geben.

+1

Mehr als geben Sie ein paar Ideen, es wird ziemlich genau das tun, was Sie wollen. – badbod99

+0

Ausgenommen, es beantwortet nicht meine größte Sorge über die Machbarkeit der Verwendung von ASP.NET als Hosting-Umgebung für asynchrone Aufgaben. Quarz, wie großartig es sein könnte, wird hier nicht helfen. –

+0

5 Jahre später und hier bin ich immer noch auf der Suche nach einem asp.net freundlichen und zuverlässigen Hintergrund Job Scheduler mit asynchronen Jobausführung –

1

Ich sage dir, was ich habe. Ich habe eine Klasse namens Atzenta, die einen Timer (1-2 Sekunden Trigger) haben. Ich habe auch eine Tabelle in meiner temporären Datenbank erstellt, die die Jobs behalten. Die Tabelle kennt die JobID, andere Parameter, Priorität, Jobstatus, Nachrichten.

Ich kann einen Job in dieser Klasse hinzufügen oder löschen. Wenn keine Aktion ausgeführt werden kann, ist der Timer gestoppt. Wenn ich einen Job hinzufüge, startet der Timer erneut. (Der Timer ist ein Thread von ihm selbst, der parallel arbeiten kann). Ich benutze das System.Timers and not other timers for this.

Die Jobs können unterschiedliche Priorität haben.

Jetzt sagen, dass ich einen Job auf diesem Tisch mit der Atzenta Klasse platzieren. Wenn der Timer das nächste Mal ausgelöst wird, überprüfen Sie die Abfrage in dieser Tabelle und suchen Sie den ersten verfügbaren Job, und führen Sie ihn einfach aus. Keine anderen Jobs laufen, bis dieser beendet ist.

Alle Synchronisierungen und Flags erfolgen aus der Tabelle. In der Tabelle habe ich Flags für jeden Job, der anzeigt, ob | er darauf wartet, dass er | ausgeführt wird | run | pause | finish |

Alle Jobs sind alle bekannte Funktionen oder Klassen (zB die Erstellung von Statistiken).

Zum Stoppen und Starten verwende ich global.asax und Application_Start, Application_End, um das Objekt zu starten und zu pausieren, das die Aufgaben behält. Zum Beispiel, wenn ich einen Job mache, und ich bekomme den Application_End Ether Ich warte, um zu beenden und dann die App zu stoppen, Ether Ich stoppe die Aktion, benachrichtigen Sie die Tabelle und starten Sie erneut auf Application_start.

Also sage ich, Atzenta.RunTheJob (Jobs.StatisticUpdate, ProductID); und dann füge ich diesen Job in die Tabelle ein, öffne den Timer, und dann wird dieser Job ausgeführt und ich aktualisiere die Statistiken für die angegebene Produkt-ID.

Ich benutze eine Tabelle in einer Datenbank, um viele Pools zu synchronisieren, die die gleiche Web-App ausführen, und tatsächlich funktioniert es so. Mit einer gemeinsamen Tabelle ist die Synchronisierung der Jobs einfach und Sie vermeiden, dass zwei Pools denselben Job zur gleichen Zeit ausführen.

In meinem Backoffice habe ich eine einfache Tabellenansicht, um den Status aller Jobs zu sehen.

+0

Ich mag das, hatten Sie irgendwelche Probleme im Zusammenhang mit der App Absturz oder auf unerwartete Weise unterbrochen? –

+0

@John Nein Ich habe keine besonderen Probleme. Ich lasse den Webservice nicht herunterfahren, aber ich öffne die app_offline.htm, wenn ich update mache, dann warte ich darauf, auf meinem Log zu sehen, dass alle Anwendungen erledigt sind - also zwinge ich sie nicht zu stoppen. Es stürzt auch nicht ab - wenn es ist, sehe ich es im Log und mache try/catch und so weiter. Wenn der Prozess auf dem Tisch aus irgendeinem Grund abgestürzt ist, verstehe ich es durch die Tatsache, dass der Status ausgeführt wird, aber ich leite derzeit nichts. Sein ein mehr einfaches Kennzeichen, das auf Datenbank gespeichert wird, die ich etwas laufen lasse. – Aristos

+0

@John einer der Prozess ist ein benutzerdefinierter Index meines Textes in der Datenbank. Am ersten Tag lief es mehr als 28 Stunden ohne Probleme. Später repariere ich einen Weg, um es zu markieren und diesen Indexer anzuhalten. – Aristos

2

Die Verwendung der Datenbank als Zustandsmechanismus ist eine vollkommen gültige Idee. Wie komplex es sein wird, hängt davon ab, wie weit Sie es nehmen wollen. In vielen Fällen werden Sie Ihre Datenbanklogik mit einem Windows-Dienst verknüpfen, um das gewünschte Ergebnis zu erzielen.

FWIW, es ist in der Regel keine gute Praxis, den Thread-Pool innerhalb einer ASP.Net-Anwendung manuell zu verwenden, obwohl es (im Gegensatz zu dem, was Sie lesen) eigentlich ganz anders als die große Einschränkung funktioniert, die Sie nicht können garantie es wird funktionieren.

Wenn Sie also einen Hintergrund-Thread benötigen, der alle 30 Sekunden den Status eines Objekts überprüft und es nicht interessiert, ob er alle 30 Sekunden oder 29 Sekunden oder 2 Minuten ausgelöst hat (z. B. in einem langen App-Pool-Recycling), Ein von ASP.Net erstellter Thread ist eine schnelle und sehr schmutzige Lösung.

Asynchron ausgelöst Callbacks (wie auf dem ASP.Net Cache-Objekt) können auch eine Art "hinter den Kulissen" Rolle ausführen.

Ich hatte ähnliche Herausforderungen und entschied mich letztendlich für einen Windows-Dienst, der eine Kombination von Bausteinen für maximale Flexibilität verwendet.Das heißt, ich benutze:

1) WCF mit umsetzungs bestimmte Arten oder

2) Typen, die gemeint sind, zu transportieren und Objekte, die einen Job wickeln ODER

3) vollständig generisch, serialisierbare Objekte enthalten in einem benutzerdefinierten Wrapper. Da sie nur eine binäre Nutzlast sind, können alle Objekte an den Dienst übergeben werden. Sobald der Wrapper im Dienst ist, definiert er, was mit dem Objekt geschehen soll (z. B. eine Methode aufrufen, ein Ergebnis sammeln und optional das Ergebnis für eine Rückkehr verfügbar machen).

Letztendlich ist die Website verantwortlich für die Abfrage des Dienstes über seinen Zustand. Diese Abfrage kann so einfach sein wie das Abfragen oder kann asynchrone Rückrufe mit WCF verwenden (obwohl ich glaube, dass dies auch eine Art von Polling hinter den Kulissen verwendet).

+0

Dank für die Antwort erwäge ich Serialisierungstypen (Senden der IL-Code) für die Ausführung in einer Remote-Umgebung. Wenn ich mit dem Windows-Service-Ansatz gehe, dann brauche ich einen wirklich flexiblen Remoting- oder Remote-Aufruf-Mechanismus, vielleicht wird WCF dies erleichtern, aber es wird immer noch viele kleine Aufgaben geben, die nur in bestimmten Code-Basen existieren und diese müssen irgendwie arbeite mit dem Service. –

+0

Ich fand die DataContract-Einschränkungen mit WCF schwer zu handhaben, wenn Sie zahlreiche Arten von Objekten an einen Service zur Remote-Ausführung senden müssen. Ich habe das verstanden, indem ich ein paar Wrapper-Objekte deklariert habe, die meine Objektbäume transportieren können (als Byte-Arrays) und einfache Anweisungen zur Verwendung dieser Objekte. Dann muss WCF nur die Schnittstellen dieser Wrapperobjekte kennen, und eine der großen Barrieren wird entfernt (IMO). Wenn Sie sagen "nur in bestimmten Codebasen existieren", meinen Sie, dass der Ausführungshost nicht in der Lage wäre, diese Typen zu referenzieren? –

+0

Offensichtlich muss der Ausführungshost in der Lage sein, diese Typen zu referenzieren, aber es ist niemals ein fester Satz von Dingen, der getan werden muss. Das ist sehr unterschiedlich. Subtile Unterschiede existieren jedoch. Ich sehe nicht, dass ich selbst eine Vielzahl von Diensten erstelle, die im Auftrag einer anderen Anwendung ausgeführt werden. –

Verwandte Themen