Delen via


Annuleringsgedrag modelleren in werkstromen

Activiteiten kunnen worden geannuleerd binnen een werkstroom, bijvoorbeeld door een Parallel activiteit die onvolledige vertakkingen annuleert wanneer CompletionCondition deze wordt geëvalueerd true, of van buiten de werkstroom, als de host aanroept Cancel. Om annuleringsafhandeling te bieden, kunnen auteurs van werkstromen de CancellationScope activiteit, de CompensableActivity activiteit of aangepaste activiteiten maken die annuleringslogica bieden. In dit onderwerp vindt u een overzicht van annulering in werkstromen.

Annulering, compensatie en transacties

Transacties bieden uw toepassing de mogelijkheid om alle wijzigingen die in de transactie worden uitgevoerd, af te breken (terug te draaien) als er fouten optreden tijdens een deel van het transactieproces. Niet alle werkzaamheden die mogelijk moeten worden geannuleerd of ongedaan moeten worden gemaakt, zijn echter geschikt voor transacties, zoals langlopend werk of werk dat geen transactionele resources omvat. Compensatie biedt een model voor het ongedaan maken van eerder voltooid niet-transactioneel werk als er een volgende fout optreedt in de werkstroom. Annulering biedt een model voor auteurs van werkstromen en activiteiten om niet-transactioneel werk af te handelen dat niet is voltooid. Als een activiteit de uitvoering niet heeft voltooid en deze wordt geannuleerd, wordt de annuleringslogica aangeroepen als deze beschikbaar is.

Notitie

Zie Transacties en compensatie voor meer informatie over transacties en compensatie.

CancellationScope gebruiken

De CancellationScope activiteit heeft twee secties die onderliggende activiteiten kunnen bevatten: Body en CancellationHandler. Hier Body worden de activiteiten geplaatst waaruit de logica van de activiteit bestaat en waar CancellationHandler de activiteiten die annuleringslogica bieden voor de activiteit worden geplaatst. Een activiteit kan alleen worden geannuleerd als deze niet is voltooid. In het geval van de activiteit verwijst voltooiing CancellationScope naar de voltooiing van de activiteiten in de Body. Als een annuleringsaanvraag is gepland en de activiteiten in de Body niet-voltooide, worden de CancellationScope activiteiten gemarkeerd als Canceled en worden de CancellationHandler activiteiten uitgevoerd.

Een werkstroom annuleren van de host

Een host kan een werkstroom annuleren door de Cancel methode aan te roepen van het WorkflowApplication exemplaar dat als host fungeert voor de werkstroom. In het volgende voorbeeld wordt een werkstroom gemaakt met een CancellationScope. De werkstroom wordt aangeroepen en vervolgens wordt de host aangeroepen.Cancel De belangrijkste uitvoering van de werkstroom wordt gestopt, de CancellationHandler aanroep van de CancellationScope werkstroom en vervolgens wordt de werkstroom voltooid met de status 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();

Wanneer deze werkstroom wordt aangeroepen, wordt de volgende uitvoer weergegeven in de console.

De werkstroom starten.
CancellationHandler aangeroepen.Werkstroom b30ebb30-df46-4d90-a211-e31c38d8db3c Geannuleerd.

Notitie

Wanneer een CancellationScope activiteit wordt geannuleerd en de CancellationHandler aangeroepen, is het de verantwoordelijkheid van de auteur van de werkstroom om de voortgang te bepalen die de geannuleerde activiteit heeft gemaakt voordat deze werd geannuleerd om de juiste annuleringslogica op te geven. Er CancellationHandler wordt geen informatie verstrekt over de voortgang van de geannuleerde activiteit.

Een werkstroom kan ook worden geannuleerd vanaf de host als een niet-verwerkte uitzondering voorbij de hoofdmap van de werkstroom komt en de OnUnhandledException handler retourneert Cancel. In dit voorbeeld wordt de werkstroom gestart en wordt er vervolgens een ApplicationException. Deze uitzondering wordt niet verwerkt door de werkstroom en daarom wordt de OnUnhandledException handler aangeroepen. De handler geeft de runtime de opdracht om de werkstroom te annuleren en de CancellationHandler huidige uitvoeringsactiviteit CancellationScope wordt aangeroepen.

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();

Wanneer deze werkstroom wordt aangeroepen, wordt de volgende uitvoer weergegeven in de console.

De werkstroom starten.
OnUnhandledException in Workflow 6bb2d5d6-f49a-4c6d-a988-478afb86dbe9Een ApplicationException is gegenereerd.CancellationHandler aangeroepen.Werkstroom 6bb2d5d6-f49a-4c6d-a988-478afb86dbe9 Geannuleerd.

Een activiteit annuleren vanuit een werkstroom

Een activiteit kan ook worden geannuleerd door de bovenliggende activiteit. Als een Parallel activiteit bijvoorbeeld meerdere uitvoeringsvertakkingen heeft en het CompletionCondition resultaat is true , worden de onvolledige vertakkingen geannuleerd. In dit voorbeeld wordt een Parallel activiteit gemaakt met twee vertakkingen. Het CompletionCondition is zo ingesteld true dat de Parallel bewerking wordt voltooid zodra een van de vertakkingen is voltooid. In dit voorbeeld wordt vertakking 2 voltooid en wordt vertakking 1 geannuleerd.

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();

Wanneer deze werkstroom wordt aangeroepen, wordt de volgende uitvoer weergegeven in de console.

Vertakking 1 begint.
Vertakking 2 is voltooid.Vertakking 1 is geannuleerd.Workflow e0685e24-18ef-4a47-acf3-5c638732f3be Completed. Activiteiten worden ook geannuleerd als een uitzondering voorbij de hoofdmap van de activiteit loopt, maar op een hoger niveau in de werkstroom wordt verwerkt. In dit voorbeeld bestaat de hoofdlogica van de werkstroom uit een Sequence activiteit. De Sequence activiteit wordt opgegeven als een Body CancellationScope activiteit die is opgenomen in een TryCatch activiteit. Er wordt een uitzondering gegenereerd uit de hoofdtekst van de Sequencehoofdtekst, wordt verwerkt door de bovenliggende TryCatch activiteit en de Sequence activiteit wordt geannuleerd.

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();

Wanneer deze werkstroom wordt aangeroepen, wordt de volgende uitvoer weergegeven in de console.

Volgorde starten.
Volgorde is geannuleerd.Uitzondering gevangen.Werkstroom e3c18939-121e-4c43-af1c-ba1ce977ce55 Voltooid.

Uitzonderingen genereren van een CancellationHandler

Eventuele uitzonderingen die worden veroorzaakt door een CancellationHandler werkstroom CancellationScope , zijn onherstelbare gevolgen voor de werkstroom. Als er een mogelijkheid is van uitzonderingen die ontsnappen uit een CancellationHandler, gebruikt u een TryCatch in de CancellationHandler om deze uitzonderingen te ondervangen en af te handelen.

Annulering met CompensableActivity

Net als bij de CancellationScope activiteit heeft het CompensableActivity een CancellationHandler. Als een CompensableActivity activiteit wordt geannuleerd, worden alle activiteiten in de CancellationHandler activiteiten ervan aangeroepen. Dit kan handig zijn voor het ongedaan maken van gedeeltelijk voltooide compensable werk. Zie Compensatie voor meer informatie over het gebruik CompensableActivity van compensatie en annulering.

Annulering met aangepaste activiteiten

Auteurs van aangepaste activiteiten kunnen op verschillende manieren annuleringslogica implementeren in hun aangepaste activiteiten. Aangepaste activiteiten die zijn afgeleid van Activity , kunnen annuleringslogica implementeren door een CancellationScope of andere aangepaste activiteit te plaatsen die annuleringslogica bevat in de hoofdtekst van de activiteit. AsyncCodeActivity en NativeActivity afgeleide activiteiten kunnen hun respectieve Cancel methode overschrijven en daar annuleringslogica bieden. CodeActivity afgeleide activiteiten bieden geen inrichting voor annulering, omdat al hun werk wordt uitgevoerd in één burst van uitvoering wanneer de runtime de Execute methode aanroept. Als de uitvoeringsmethode nog niet is aangeroepen en een CodeActivity op basisactiviteit wordt geannuleerd, wordt de activiteit gesloten met de status en Canceled wordt de Execute methode niet aangeroepen.

Annulering met NativeActivity

NativeActivity afgeleide activiteiten kunnen de Cancel methode overschrijven om aangepaste annuleringslogica te bieden. Als deze methode niet wordt overschreven, wordt de standaardlogica voor het annuleren van werkstromen toegepast. Standaardannulering is het proces dat plaatsvindt voor een methode NativeActivity die de Cancel methode niet overschrijft of waarvan Cancel de methode de basismethode NativeActivity Cancel aanroept. Wanneer een activiteit wordt geannuleerd, markeert de runtime de activiteit voor annulering en wordt bepaalde opschoning automatisch afgehandeld. Als de activiteit alleen openstaande bladwijzers heeft, worden de bladwijzers verwijderd en wordt de activiteit gemarkeerd als Canceled. Alle openstaande onderliggende activiteiten van de geannuleerde activiteit worden op hun beurt geannuleerd. Als u extra onderliggende activiteiten plant, wordt de poging genegeerd en wordt de activiteit gemarkeerd als Canceled. Als een openstaande onderliggende activiteit in de Canceled of Faulted status is voltooid, wordt de activiteit gemarkeerd als Canceled. Houd er rekening mee dat een annuleringsaanvraag kan worden genegeerd. Als een activiteit geen openstaande bladwijzers heeft of onderliggende activiteiten uitvoert en geen extra werkitems plant nadat deze is gemarkeerd voor annulering, wordt deze voltooid. Deze standaardannulering volstaat voor veel scenario's, maar als er extra annuleringslogica nodig is, kunnen de ingebouwde annuleringsactiviteiten of aangepaste activiteiten worden gebruikt.

In het volgende voorbeeld wordt de Cancel onderdrukking van een aangepaste activiteit op basis van een NativeActivity aangepaste ParallelForEach activiteit gedefinieerd. Wanneer de activiteit wordt geannuleerd, wordt met deze onderdrukking de annuleringslogica voor de activiteit verwerkt. Dit voorbeeld maakt deel uit van het Non-Generic ParallelForEach-voorbeeld .

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 afgeleide activiteiten kunnen bepalen of annulering is aangevraagd door de IsCancellationRequested eigenschap te inspecteren en zichzelf te markeren als geannuleerd door de methode aan te MarkCanceled roepen. Het aanroepen MarkCanceled voltooit de activiteit niet onmiddellijk. Zoals gebruikelijk voltooit de runtime de activiteit wanneer deze geen openstaand werk meer heeft, maar als MarkCanceled de uiteindelijke status wordt genoemd, in Canceled plaats van Closed.

Annulering met behulp van AsyncCodeActivity

AsyncCodeActivity op basis van activiteiten kan ook aangepaste annuleringslogica bieden door de Cancel methode te overschrijven. Als deze methode niet wordt overschreven, wordt er geen annuleringsafhandeling uitgevoerd als de activiteit wordt geannuleerd. In het volgende voorbeeld wordt de Cancel onderdrukking van een AsyncCodeActivity aangepaste ExecutePowerShell activiteit op basis gedefinieerd. Wanneer de activiteit wordt geannuleerd, wordt het gewenste annuleringsgedrag uitgevoerd.

// 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 afgeleide activiteiten kunnen bepalen of annulering is aangevraagd door de IsCancellationRequested eigenschap te inspecteren en zichzelf te markeren als geannuleerd door de methode aan te MarkCanceled roepen.