void WorkItemCreating()
Bevor ein (noch nicht laufendes) Work-Item vom Work-Manager eingeplant oder aktualisiert wird, wird die Methode aufgerufen. Darin kann das Work-Item eigene Eigenschaften berechnen, die mehr Informationen brauchen als dem Konstruktor zur Verfügung stehen.
Die Standardimplementierung ist leer.
void WorkItemShouldFinish()
Diese Methode wird aufgerufen, wenn ein laufendes Work-Item abgebrochen werden soll. Das gibt dem Work-Item die Möglichkeit, asynchron auf ein solches Event zu reagieren, und beispielsweise ein ManualResetEvent
zu setzen.
Die Standardimplementierung schreibt eine Warnung über dieses Ereignis ins Applikationsprotokoll, falls dieses aktiv ist.
void WorkItemFinished()
Diese Methode wird für jedes Work-Item genau einmal ausgeführt, das der Work-Manager einmal zu Gesicht bekommen hat. Was dann tatsächlich passiert, ist der Eigenschaft “State” zu entnehmen:
Finished
Die Methode Run ist ordnungsgemäß zurückgekehrt oder das Work-Item wurde zwar abgebrochen, aber es war sowieso gerade fertig (CurrentProgress == MaxProgress
)Removed
Das Work-Item war schon einmal eingeplant und wurde, bevor es starten konnte abgebrochen.Cancelled
Das Work-Item hat auf eine Abbruchanforderung durch den Benutzer reagiert und sich selbst beendet.Timeout
Das Work-Item hat die maximale Verarbeitungsdauer überschritten und sich daraufhin beendet.
Die Standardimplementierung würde hier eine automatische Neueinplanung versuchen, solangeMaxNumberOfRestarts
noch nicht erreicht ist.Killed
Das Work-Item hat die maximale Verarbeitungsdauer überschritten und sich daraufhin binnen der gesetzten Nachfrist nicht beendet.Error
Die Run-Methode ist mit einer unbehandelten Ausnahmen abgebrochen. Diese steht inExceptionDuringRun
.
Die Standardimplementierung protokolliert die Ausnahme mitLogCriticalError
und versucht einen Neueinplanung, solangeMaxNumberOfRestarts
noch nicht erreicht ist.Aborted
Die Ausführung wurde durch einen Anwendungsneustart unerwartet unterbrochen. Dieser Aufruf erfolgt natürlich erst nach dem Neustart der Anwendung.
Die Standardimplementierung versucht hier immer einen Neustart, unabhängig vonMaxNumberOfRestarts
.
Wenn sich das Work-Item nach der Ausführung der Methode neu eingeplant hat, wechselt der Status von Finished
auf Reschedule
, von Timeout
auf TimeoutRetry
und von Error
auf ErrorRetry
.
Überschriebene Implementierungen sollten im allgemeinen base.WorkItemFinished()
in den Fällen aufrufen, die sie nicht selbst explizit behandelt haben. Nur dadurch ist sichergestellt, dass Worker z.B. nach einem Anwendungsneustart auch wirklich wieder starten.
Ferner sollte die Methode nicht selbst Save aufrufen. Das würde die transaktionale Integrität brechen. Das Work-Item wird danach immer automatisch gespeichert.
Ebenfalls sollten keine aufwändige Berechnungen in der Methode erfolgen. Für die Ausführung steht nur ein enges Zeitkontingent von einer Minute zur Verfügung. Danach wird der Worker unwiderruflich abgebrochen. Auch ein wiederholt eingeplanter Worker würde nach einem solchen Abbruch nie wieder laufen.
Beispiel, um nach einem (bestätigten) Timeout beliebig oft und ohne Karenzzeit dazwischen neu zu starten – das entspricht logisch Thread.Yield()
:
protected override void WorkItemFinished()
{
if (State == EnumWorkItemState.Timeout)
AddSuccessor(TimeSpan.Zero);
else
base.WorkItemFinished();
}
InitLogger()
Diese Methode wird vor der eigentlichen Ausführung eines Work-Items aufgerufen, wenn IsLoggingEnabled
aktiviert ist. Alternativ kann die Methode auch selbst aufgerufen werden, wenn eine verzögerte bzw. bedingte Anlage des Protokolls gewünscht ist. Dann muss LoggerGuid
leer sein.
Die Standardimplementierung legt ein neues Applikationsprotokoll an, wenn LoggerGuid
leer ist oder öffnet ein bestehendes Protokoll wenn einer LoggerGuid
angegeben wurde. Nachher ist LoggerGuid
immer gefüllt. Dadurch ist sichergestellt, dass nach Neustarts im selben Protokoll fortgefahren wird.
Die Methode kann überschrieben werden, um abweichende Logging-Verfahren zu implementieren. beispielsweise täglich rollierende Logs.
CreateSuccsessor()
Das ist faktisch eine Klon-Methode. Sie erstellt eine Kopie des Work-Items. Dabei werden alle persistierten Eigenschaften des Work-Items übernommen, mit folgenden Ausnahmen:
State
ist immerIdle
(Standard für neue Items)ScheduledStartTime
wird auf die aktuelle Uhrzeit gesetzt, also sofort einplanen.NumberOfStarts
wird nicht übernommen. Das muss explizit selbst gemacht werden, wenn erwünscht ist, dass bei dieser Neueinplanung der Countdown fürMaxNumberOfRestarts
läuft.
Eigene Worker können diese Methode überschreiben, um ein abweichendes Verhalten zu implementieren. Das gilt dann für alle per AddSuccessor
erzeugten Nachfolger einschließlich automatischer Neustarts nach Fehlern.
Beim Überschreiben sollte immer zuerst die Standardimplementierung base.CreateSuccessor()
aufgerufen werden.