Modelowanie zachowania anulowania w przepływach pracy
Działania można anulować wewnątrz przepływu pracy, na przykład przez Parallel działanie anulujące niekompletne gałęzie, gdy zostanie obliczona CompletionCondition wartość true
, lub spoza przepływu pracy, jeśli host wywołuje Cancelmetodę . Aby zapewnić obsługę anulowania, autorzy przepływów pracy mogą używać CancellationScope działania, CompensableActivity działania lub tworzenia niestandardowych działań zapewniających logikę anulowania. Ten temat zawiera omówienie anulowania w przepływach pracy.
Anulowanie, odszkodowanie i transakcje
Transakcje dają aplikacji możliwość przerwania (wycofania) wszystkich zmian wykonywanych w ramach transakcji, jeśli wystąpią jakiekolwiek błędy w jakiejkolwiek części procesu transakcji. Jednak nie wszystkie prace, które mogą wymagać anulowania lub cofnięcia, są odpowiednie dla transakcji, takich jak długotrwała praca lub praca, która nie obejmuje zasobów transakcyjnych. Rekompensata zapewnia model umożliwiający cofnięcie wcześniej ukończonej pracy nie transakcyjnej, jeśli w przepływie pracy wystąpi kolejna awaria. Anulowanie udostępnia model dla autorów przepływów pracy i działań do obsługi pracy nie transakcyjnej, która nie została ukończona. Jeśli działanie nie zostało ukończone i zostanie anulowane, jego logika anulowania zostanie wywołana, jeśli jest dostępna.
Uwaga
Aby uzyskać więcej informacji na temat transakcji i odszkodowania, zobacz Transakcje i Rekompensata.
Używanie działania CancellationScope
Działanie CancellationScope zawiera dwie sekcje, które mogą zawierać działania podrzędne: Body i CancellationHandler. Jest Body to miejsce, w którym są umieszczane działania tworzące logikę działania, a CancellationHandler jest to miejsce, w którym są umieszczane działania, które zapewniają logikę anulowania dla działania. Działanie można anulować tylko wtedy, gdy nie zostało ukończone. W przypadku CancellationScope działania ukończenie odnosi się do ukończenia działań w obiekcie Body. Jeśli żądanie anulowania zostało zaplanowane, a działania w obiekcie Body nie zostały ukończone, CancellationScope zostaną oznaczone jako Canceled i CancellationHandler działania zostaną wykonane.
Anulowanie przepływu pracy z hosta
Host może anulować przepływ pracy, wywołując Cancel metodę WorkflowApplication wystąpienia hostujące przepływ pracy. W poniższym przykładzie tworzony jest przepływ pracy z elementem CancellationScope. Przepływ pracy jest wywoływany, a następnie host wywołuje metodę Cancel. Główne wykonanie przepływu pracy jest zatrzymywane, CancellationHandler wywoływany jest element CancellationScope , a następnie przepływ pracy kończy się stanem Canceled.
Activity wf = new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Starting the workflow."
},
new Delay
{
Duration = TimeSpan.FromSeconds(5)
},
new WriteLine
{
Text = "Ending the workflow."
}
}
},
CancellationHandler = new WriteLine
{
Text = "CancellationHandler invoked."
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
// Subscribe to any desired workflow lifecycle events.
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
Console.WriteLine("Exception: {0}\n{1}",
e.TerminationException.GetType().FullName,
e.TerminationException.Message);
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
}
else
{
Console.WriteLine("Workflow {0} Completed.", e.InstanceId);
}
};
// Run the workflow.
wfApp.Run();
Thread.Sleep(TimeSpan.FromSeconds(1));
wfApp.Cancel();
Po wywołaniu tego przepływu pracy następujące dane wyjściowe zostaną wyświetlone w konsoli programu .
Uruchamianie przepływu pracy.
Wywołano procedurę anulowania.Przepływ pracy b30ebb30-df46-4d90-a211-e31c38d8db3c Anulowano.
Uwaga
CancellationScope Po anulowaniu działania i CancellationHandler wywołaniu jest to odpowiedzialność autora przepływu pracy w celu określenia postępu anulowanego działania dokonanego przed jego anulowaniem w celu zapewnienia odpowiedniej logiki anulowania. Element CancellationHandler nie zawiera żadnych informacji o postępie anulowanego działania.
Przepływ pracy można również anulować z hosta, jeśli nieobsługiwany wyjątek bąbelkuje obok katalogu głównego przepływu pracy, a OnUnhandledException program obsługi zwraca wartość Cancel. W tym przykładzie przepływ pracy zostanie uruchomiony, a następnie wyrzucony element ApplicationException. Ten wyjątek jest nieobsługiwany przez przepływ pracy i dlatego jest wywoływany OnUnhandledException program obsługi. Procedura obsługi instruuje środowisko uruchomieniowe, aby anulowało przepływ pracy, a CancellationHandler aktualnie wykonywane CancellationScope działanie jest wywoływane.
Activity wf = new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Starting the workflow."
},
new Throw
{
Exception = new InArgument<Exception>((env) =>
new ApplicationException("An ApplicationException was thrown."))
},
new WriteLine
{
Text = "Ending the workflow."
}
}
},
CancellationHandler = new WriteLine
{
Text = "CancellationHandler invoked."
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
// Subscribe to any desired workflow lifecycle events.
wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
// Display the unhandled exception.
Console.WriteLine("OnUnhandledException in Workflow {0}\n{1}",
e.InstanceId, e.UnhandledException.Message);
// Instruct the runtime to cancel the workflow.
return UnhandledExceptionAction.Cancel;
};
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
Console.WriteLine("Exception: {0}\n{1}",
e.TerminationException.GetType().FullName,
e.TerminationException.Message);
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
}
else
{
Console.WriteLine("Workflow {0} Completed.", e.InstanceId);
}
};
// Run the workflow.
wfApp.Run();
Po wywołaniu tego przepływu pracy następujące dane wyjściowe zostaną wyświetlone w konsoli programu .
Uruchamianie przepływu pracy.
OnUnhandledException in Workflow 6bb2d5d6-f49a-4c6d-a988-478afb86dbe9An ApplicationException został zgłoszony.Wywołano procedurę anulowania.Przepływ pracy 6bb2d5d6-f49a-4c6d-a988-478afb86dbe9 Anulowane.
Anulowanie działania z poziomu przepływu pracy
Działanie można również anulować przez jego element nadrzędny. Jeśli na przykład Parallel działanie ma wiele wykonujących gałęzie, a jego CompletionCondition oceny do true
tego celu, jego niekompletne gałęzie zostaną anulowane. W tym przykładzie zostanie Parallel utworzone działanie, które ma dwie gałęzie. Jego CompletionCondition wartość jest ustawiona na wartość , aby Parallel ukończyć true
każdą z jego gałęzi, gdy tylko zostanie ukończona. W tym przykładzie gałąź 2 zostanie ukończona, dlatego gałąź 1 zostanie anulowana.
Activity wf = new Parallel
{
CompletionCondition = true,
Branches =
{
new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Branch 1 starting."
},
new Delay
{
Duration = TimeSpan.FromSeconds(2)
},
new WriteLine
{
Text = "Branch 1 complete."
}
}
},
CancellationHandler = new WriteLine
{
Text = "Branch 1 canceled."
}
},
new WriteLine
{
Text = "Branch 2 complete."
}
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
Console.WriteLine("Exception: {0}\n{1}",
e.TerminationException.GetType().FullName,
e.TerminationException.Message);
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
}
else
{
Console.WriteLine("Workflow {0} Completed.", e.InstanceId);
}
};
// Run the workflow.
wfApp.Run();
Po wywołaniu tego przepływu pracy następujące dane wyjściowe zostaną wyświetlone w konsoli programu .
Początek gałęzi 1.
Gałąź 2 ukończona.Gałąź 1 została anulowana.Przepływ pracy e0685e24-18ef-4a47-acf3-5c638732f3be Ukończono. Działania są również anulowane, jeśli wyjątek jest bąbelkowy obok katalogu głównego działania, ale jest obsługiwany na wyższym poziomie w przepływie pracy. W tym przykładzie główna logika przepływu pracy składa się z Sequence działania. Parametr Sequence jest określony jako Body CancellationScope działanie, które jest zawarte w TryCatch działaniu. Wyjątek jest zgłaszany z treści Sequenceobiektu , jest obsługiwany przez działanie nadrzędne TryCatch , a element Sequence jest anulowany.
Activity wf = new TryCatch
{
Try = new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Sequence starting."
},
new Throw
{
Exception = new InArgument<Exception>((env) =>
new ApplicationException("An ApplicationException was thrown."))
},
new WriteLine
{
Text = "Sequence complete."
}
}
},
CancellationHandler = new WriteLine
{
Text = "Sequence canceled."
}
},
Catches =
{
new Catch<ApplicationException>
{
Action = new ActivityAction<ApplicationException>
{
Handler = new WriteLine
{
Text = "Exception caught."
}
}
}
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
Console.WriteLine("Exception: {0}\n{1}",
e.TerminationException.GetType().FullName,
e.TerminationException.Message);
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
}
else
{
Console.WriteLine("Workflow {0} Completed.", e.InstanceId);
}
};
// Run the workflow.
wfApp.Run();
Po wywołaniu tego przepływu pracy następujące dane wyjściowe zostaną wyświetlone w konsoli programu .
Uruchamianie sekwencji.
Anulowano sekwencję.Przechwycony wyjątek.Przepływ pracy e3c18939-121e-4c43-af1c-ba1ce977ce55 Ukończono.
Zgłaszanie wyjątków z procedury obsługi anulowania
Wszelkie wyjątki zgłaszane z CancellationHandler elementu CancellationScope są krytyczne dla przepływu pracy. Jeśli istnieje możliwość wyjątków ucieczki z obiektu CancellationHandler, użyj elementu TryCatch w CancellationHandler , aby przechwycić i obsłużyć te wyjątki.
Anulowanie przy użyciu funkcji CompensableActivity
Podobnie jak działanie CancellationScope , element CompensableActivity ma wartość CancellationHandler. Jeśli element CompensableActivity zostanie anulowany, wszystkie działania w jego CancellationHandler elementy są wywoływane. Może to być przydatne w przypadku cofania częściowo ukończonej pracy z możliwością wykonania. Aby uzyskać informacje o sposobie korzystania z CompensableActivity odszkodowania i anulowania, zobacz Rekompensata.
Anulowanie przy użyciu działań niestandardowych
Autorzy działań niestandardowych mogą implementować logikę anulowania w swoich niestandardowych działaniach na kilka różnych sposobów. Działania niestandardowe pochodzące z Activity programu mogą implementować logikę anulowania przez umieszczenie CancellationScope lub innego niestandardowego działania, które zawiera logikę anulowania w treści działania. AsyncCodeActivity i NativeActivity pochodne działania mogą zastąpić odpowiednią Cancel metodę i zapewnić tam logikę anulowania. CodeActivity Działania pochodne nie zapewniają żadnej aprowizacji anulowania, ponieważ wszystkie ich prace są wykonywane w jednym wybuchu wykonywania, gdy środowisko uruchomieniowe wywołuje metodę Execute . Jeśli metoda execute nie została jeszcze wywołana, a CodeActivity działanie oparte zostanie anulowane, działanie zostanie zamknięte ze stanem Canceled i Execute metoda nie zostanie wywołana.
Anulowanie przy użyciu elementu NativeActivity
NativeActivity Działania pochodne mogą zastąpić metodę w celu zapewnienia niestandardowej Cancel logiki anulowania. Jeśli ta metoda nie zostanie zastąpiona, zostanie zastosowana domyślna logika anulowania przepływu pracy. Domyślne anulowanie to proces, który występuje dla elementu NativeActivity , który nie zastępuje Cancel metody lub której Cancel metoda wywołuje metodę podstawową NativeActivity Cancel . Po anulowaniu działania środowisko uruchomieniowe flaguje działanie anulowania i automatycznie obsługuje pewne czyszczenie. Jeśli działanie zawiera tylko zaległe zakładki, zakładki zostaną usunięte, a działanie zostanie oznaczone jako Canceled. Wszelkie zaległe działania podrzędne anulowanego działania zostaną anulowane. Każda próba zaplanowana dodatkowych działań podrzędnych spowoduje zignorowanie próby, a działanie zostanie oznaczone jako Canceled. Jeśli jakiekolwiek zaległe działanie podrzędne zakończy się w Canceled stanie lub Faulted , działanie zostanie oznaczone jako Canceled. Należy pamiętać, że żądanie anulowania można zignorować. Jeśli działanie nie ma żadnych zaległych zakładek ani wykonywania działań podrzędnych i nie planuje żadnych dodatkowych elementów roboczych po oflagowaniu w celu anulowania, zakończy się pomyślnie. To domyślne anulowanie jest wystarczające w wielu scenariuszach, ale jeśli jest wymagana dodatkowa logika anulowania, można użyć wbudowanych działań anulowania lub niestandardowych działań.
W poniższym przykładzie Cancel zdefiniowano przesłonięcia opartego na działaniu niestandardowym NativeActivity ParallelForEach
. Po anulowaniu działania to zastąpienie obsługuje logikę anulowania działania. Ten przykład jest częścią przykładu Non-Generic ParallelForEach .
protected override void Cancel(NativeActivityContext context)
{
// If we do not have a completion condition then we can just
// use default logic.
if (this.CompletionCondition == null)
{
base.Cancel(context);
}
else
{
context.CancelChildren();
}
}
NativeActivity Działania pochodne mogą określać, czy żądanie anulowania zostało żądane przez sprawdzenie IsCancellationRequested właściwości i oznaczenie się jako anulowane przez wywołanie MarkCanceled metody . Wywołanie MarkCanceled nie powoduje natychmiastowego ukończenia działania. Jak zwykle środowisko uruchomieniowe zakończy działanie, gdy nie ma więcej zaległej pracy, ale jeśli MarkCanceled jest wywoływany stan końcowy, będzie Canceled to zamiast Closed.
Anulowanie przy użyciu funkcji AsyncCodeActivity
AsyncCodeActivity Działania oparte mogą również udostępniać niestandardową logikę anulowania, przesłaniając metodę Cancel . Jeśli ta metoda nie zostanie zastąpiona, nie zostanie wykonana żadna obsługa anulowania, jeśli działanie zostanie anulowane. W poniższym przykładzie Cancel zdefiniowano przesłonięcia opartego na działaniu niestandardowym AsyncCodeActivity ExecutePowerShell
. Po anulowaniu działania wykonuje żądane zachowanie anulowania.
// Called by the runtime to cancel the execution of this asynchronous activity.
protected override void Cancel(AsyncCodeActivityContext context)
{
Pipeline pipeline = context.UserState as Pipeline;
if (pipeline != null)
{
pipeline.Stop();
DisposePipeline(pipeline);
}
base.Cancel(context);
}
AsyncCodeActivity Działania pochodne mogą określać, czy żądanie anulowania zostało żądane przez sprawdzenie IsCancellationRequested właściwości i oznaczenie się jako anulowane przez wywołanie MarkCanceled metody .