Der Work-Manager

Der Work-Manager ist Teil der BA Core Infrastruktur. Er verwaltet alle geplanten, laufenden oder beendeten Hintergrundprozesse. Dabei achtet er auf Priorisierung und maximalen Ressourcenverbrauch.

Ablauf des Work-Managers

Start

  • Beim Start der Anwendung werden alle Work-Items aus der Datenbank ausgelesen, die nicht abgeschlossen sind.
    1. Bei angeblich laufenden, also abgebrochenen Elementen wird der Status nun auf Aborted gesetzt und der Work-Manager führt asynchron die WorkItemFinished Methode aus.
    2. Bei wartenden Work-Items wird geprüft, ob sie bereit zur Ausführung sind, und der Status ggf. auf Queued geändert.
    3. Items, die sofort bereit sind, bleiben unverändert.
  • Danach werden die verfügbaren Prozesse nach Priorität der Items an die Items im Status “bereit” verteilt.
  • Zuletzt wird ein Timer für den Startzeitpunkt des nächsten wartenden Items gesetzt, falls eines existiert.

Abarbeitung

Der Work-Manager ist komplett Ereignisgetrieben. Er tut nur Etwas wenn

  1. sich ein Item beendet. Dann prüft er ob ein anderes den freiwerdenden Prozess nutzen kann.
  2. ein neues Item eingeplant oder aktualisiert wird. Dann prüft er, ob es sofort bereit zu Ausführung ist und ob dafür ein Prozess frei ist.
  3. ein Item abgebrochen werden soll. Dann signalisiert er dem Item, den Wunsch abzubrechen. Dieses setzt daraufhin asynchron seinen Status auf CancellingByUser.
  4. der Timer für die nächste Startzeit angesprochen hat. Dann setzt er den Status aller Items, deren Startzeitpunkt verstrichen ist auf Queued und prüft, ob dafür sofort ein Prozess frei ist. Anschließend wird der Timer auf das nächste Item neu programmiert.

Work-Items

Work-Items machen die eigentliche Arbeit. Work-Items sind Instanzen der serialisierbaren Worker-Klassen und Zeilen in Tabelle OrmWorkItem. Die Worker Klassen sind immer individuell für den Anwendungfall.

  • Jede Art einer Aufgabe hat eine implementierende Klasse.
  • Jede zu erledigende Aufgabe hat genau eine InstanceGuid. Die Aufgabe wird in der API immer über diese identifiziert.
  • Zu einer Aufgabenart kann es beliebig viele Aufgaben geben.
  • Jede Instanz eines Work-Items hat eine Oid. Diese ist nur intern.
  • Eine Aufgabe kann in mehreren Teilschritten (Instanzen) erledigt werden, z.B. wegen Unterbrechung durch Anwendungsneustart.
  • Instanzen entstehen, wenn sie eingeplant werden, und sind am Ende ihrer Lebensdauer, wenn sie Abgeschlossen oder aus irgendeinem Grund abgebrochen sind.
  • Die Priorität eines Work-Items ist SchedulingPriority sowie die geplante Startzeit.

Mögliche Zustände

• Bei allen Zuständen, bei denen das WorkItem noch nicht (=nie) ausgeführt wurde, gehört die Instanz dem Work-Manager. Nur er darf Veränderungen vornehmen.
• Bei allen Zuständen ab dem Start der Ausführung gehört die Instanz dem WorkItem selbst. Nur dieses darf noch Veränderungen vornehmen.
• Ab dem Start der Ausführung ist der Zustand von Instanzen von Work-Items ein gerichteter Graph.
• Die Zustände gehören zu Kategorien, die sich bezüglich vieler Eigenschaften gleich verhalten. 

Kategorie Zustand Beschreibung
Warten auf Startbedingung Idle Das Work-Item liegt in der Datenbank und wartet bis der Zeitpunkt für seine Ausführung gekommen ist.
Warten auf Ausführung Queued Das Work-Item soll ausgeführt werden und es ist bereits in der Warteschlange.
Warten auf Ausführung Removing Das Work-Item wurde von Benutzer (bzw. über die API) abgebrochen, bevor es gestartet wurde. Die Abbruchfunktion wird ebenfalls asynchron über die Warteschlange ausgeführt.
Laufend Running Das Work-Item wird gerade ausgeführt.
Laufend CancellingByUser Das Work-Item hat den Befehl zum Abbrechen bekommen und sollte sich in Kürze beenden.
Laufend CancellingBySystem Das Work-Item hat seine max. Ausführungszeit erreicht und wird in Kürze gekillt. Spätestens jetzt sollte es seine Arbeit geordnet beenden und ggf. einen nächsten Start einplanen.
Beendet Finished Das Work-Item hat seine Arbeit erfolgreich abgeschlossen.
Beendet Removed Das Work-Item wurde vor dem normalen Start abgebrochen und hatte Gelegenheit, um darauf zu reagieren.
Beendet Cancelled Das Work-Item wurde vom Benutzer (bzw. über die API) abgebrochen und hat sich selbst beendet.
Beendet Error Eine unbehandelte Ausnahme ist aufgetreten. Das WorkItem wird in Kürze neu gestartet (wenige male).
Beendet Timeout Das Work-Item hat auf den CancellingBySystem Status reagiert und sich selbst beendet.
Beendet Killed Das Work-Item hat seine Arbeit nicht binnen der gesetzten Zeit beendet und wurde vom Work-Manager gekillt – gefährlich!
Neustart Reschedule Das Work-Item wird (wegen eines Timeouts oder sonstiger Limitierungen) seine Arbeit bald wieder fortsetzen.
Neustart ErrorRetry Das Work-Item wurde nach einer Exception neu eingeplant und wird seine Arbeit bald in einer neuen Instanz fortsetzen.
Neustart TimeoutRetry Das Work-Item wurde nach einem Timeout neu eingeplant und wird seine Arbeit bald in einer neuen Instanz fortsetzen.
Neustart Aborted Das Work-Item wurde nach einem Abbruch durch einen Anwendungsneustart wieder eingeplant.

Statusübergänge

Worker Status Übergänge

Scheduling-Prioritäten

Die Priorität eines Work-Items ergibt sich aus dem Wert von ExpectedRuntime. Es gibt folgende vordefinierten Prioritäten:

  1. Urgent Work-Items mit dieser Priorität werden immer sofort ausgeführt, ohne Rücksicht auf irgendwelche Ressourcen. Die Maximale Laufzeit beträgt 1 Minute.
  2. Short Diese Work-Items werden mit normaler CPU-Priorität in der Queue für normale Work-Prozesse ausgeführt. Die Maximale Laufzeit beträgt standardmäßig 1 Minute.
  3. Normal Work-Items mit “Normal” werden mit reduzierter CPU-Priorität in der Queue für normale Work-Prozesse ausgeführt. Die Maximale Laufzeit beträgt standardmäßig 15 Minuten.
  4. Long Diese Work-Items werden mit reduzierter CPU-Priorität in einer separaten Queue für Langläufer ausgeführt. Die Maximale Laufzeit beträgt standardmäßig 5 Stunden.
    Per Konfigurationsdatei Customer.config auf dem Webserver können die maximalen Ausführungszeiten für die Prioritätsstufen angepasst werden.

Per programatischer Erweiterung von EnumExpectedRuntime können in Projekten zusätzliche Prioritätsstufen geschaffen werden. In den Eigenschaften des Auswahllistenwertes werden die Details angegeben.

Queues und Parallelität

Die Anzahl der gleichzeitig ausgeführten Work-Items (mit Ausnahme Priorität Urgent) ist begrenzt. Es wird eine Feste Anzahl von Work-Prozessen in 2 Queues vorgehalten:

  1. Normal
    In dieser Queue werden nur Work-Items der Prioritäten Short und Normal ausgeführt.
    Standardmäßig stehen dafür ¼ der auf dem Webserver verfügbaren CPU-Kerne zur Verfügung.
  2. Langläufer
    Die Queue für Langläufer führt alle Arten von Work-Items (außer Urgent) aus.
    Standardmäßig stehen dafür die Hälfte der auf dem Webserver verfügbaren CPU-Kerne zur Verfügung.

Der Start der Work-Items erfolgt immer nach Priorität. Wenn also ein Prozess frei ist, wird immer das nächste Short-Item zuerst ausgeführt, auch wenn es ein Platz in der Langläufer-Queue ist. Ein bereits laufendes Work-Item wird aber nicht unterbrochen, um einem höher priorisiertem Work-Item Platz zu machen. Nur Durch die Reservierung von Prozessen in der Normal-Queue ist sichergestellt, dass Langläufer nicht alle höher priorisierten Items aufhalten können.
Per Konfigurationsdatei Customer.config auf dem Webserver kann die Anzahl der parallelen Prozesse pro Queue verändert werden.

Lebenszyklus von Work-Items

  • Eine Instanz entsteht nur, wenn sie über die Work-Manager-API eingeplant wird.
  • Eine noch nicht gestartete Instanz kann über eine erneute Einplanung mit derselben InstanceGuid beliebig verändert werden.
  • Für jede Instanz (gleiche Oid) wird genau einmal die Methode WorkItemFinished aufgerufen, auch bei einem Abbruch vor dem Start.
  • Wenn eine Instanz vor dem Start aktualisiert wird, wird das nicht als neue Instanz betrachtet. Deshalb wird für die alte, überschriebene Version nicht WorkItemFinished aufgerufen. Das ist die einzige Konstellation, in der WorkItemFinished nicht für jede technische Instanz des Work-Items aufgerufen wird.
  • Jede Instanz endet immer in einem finalen Status oder mit einem Neustart.

Informationen über Work-Items

Neben dem vollen Work-Item gibt es eine abgespeckte Version von Work-Item-Instanzen: WorkItemProgress. Diese wird verwendet um Informationen über ein Work-Item zu liefern. Diese Informationen entstammen vollständig den nicht serialisierten Spalten aus OrmWorkItem und sind von außen nur lesbar. Nur das Work-Item selbst darf einige der Informationen verändern.

Laufzeitüberwachung

Sobald laufende Work-Items die maximale Laufzeit überschreiten bekommen sie das Signal CancellingBySystem. Sie können auf dieses Signal mit einer Frist von standardmäßig 5 Minuten reagieren, indem sie sich selbst beenden. Sie gehen dann in den Status TimeOut über. Standardmäßig wird die Implementierung von WorkItemFinished sie daraufhin MaxNumberOfRestarts mal neu einplanen.

Reagieren sie nicht in der gesetzten Frist, wird der Worker Thread hart gekillt, indem eine ThreadAbortException injiziert wird. Der Status des Work-Items wird danach auf Killed gesetzt. Dieser Zustand sollte auf jeden Fall vermieden werden, da er den Datenbestand unter Umständen in einem inkonsistenten Zustand zurücklassen kann.

Die Methode WorkItemFinished wird aber dennoch noch aufgerufen. Aber auch diese Ausführungszeit ist auf eine Minute begrenzt.