Trvalé orchestrace

Trvalá orchestrace využívá funkci orchestrátoru ke koordinaci provádění dalších funkcí ve spolehlivém dlouhotrvajícím pracovním postupu definovaném zcela v kódu. Funkce orchestrátoru mají následující charakteristiky:

  • Definují pracovní postupy pomocí procedurálního kódu. Nejsou potřeba žádná deklarativní schémata ani návrháři.
  • Volají ostatní funkce synchronně a asynchronně. Můžete uložit výstup z volaných funkcí do lokálních proměnných.
  • Automaticky kontrolují průběh vykonávání, když funkce volá operátora await OR yield , takže proces neztratí lokální stav při recyklaci nebo restartu VM.
  • Podporují dlouhotrvající procesy. Celková životnost instance orchestrace může být sekundy, dny nebo měsíce nebo můžete instanci nakonfigurovat tak, aby nikdy nekončila.

Tento článek obsahuje přehled trvalých orchestrací, včetně identity orchestrace, modelu Event Sourcing, historie spouštění a běžných vzorů pracovních postupů, jako jsou dílčí orchestrace, trvalé časovače a zpracování chyb.

Informace o typech funkcí dostupných v aplikaci Durable Functions naleznete v programovacím modelu Durable Task.

Návod

Pokud použijete C# s .NET isolated worker modelem, můžete orchestrace psát buď pomocí funkčního přístupu (statické metody s [Function] atributy), nebo třídního přístupu (třídy, které dědí z TaskOrchestrator<TInput, TOutput>). Přístup založený na třídách vyžaduje balíček zdrojového generátoru Microsoft.DurableTask.Generators a poskytuje silně typovaná volání. Další informace najdete v tématu Generátory zdrojů a syntaxe založená na třídách. Příklady kódu jazyka C# v tomto článku ukazují oba přístupy.

Sady Durable Task SDK poskytují stejné funkce orchestratoru jako Durable Functions pro vytváření spolehlivých dlouhotrvajících pracovních postupů s paralelním zpracováním a koordinací řízenou událostmi. Na rozdíl od Durable Functions se orchestrace sady Durable Task SDK spouští jako samostatné aplikace zálohované plánovačem trvalých úloh.

Identita orchestrace

Každá instance orchestrace má identifikátor instance, označovaný také jako ID instance. Ve výchozím nastavení je každé ID instance automaticky vygenerovaný globálně jedinečný identifikátor (GUID). Nicméně jako ID instance můžete použít jakoukoli řetězcovou hodnotu vygenerovanou uživatelem. Každé ID instance orchestrace musí být jedinečné v rámci centra úloh.

Následující pravidla platí pro ID instancí:

  • Musí mít délku 1 až 100 znaků.
  • Nesmí začínat @.
  • Nesmí obsahovat /znak , \, #ani ? znaky.
  • Nesmí obsahovat řídicí znaky.

Poznámka:

Id automaticky vygenerovaných instancí používejte, kdykoli je to možné. Používejte uživatelsky generované ID instancí pro situace, kdy existuje jednoznačné mapování mezi orchestrační instancí a externí aplikační entitou, například nákupní objednávkou nebo dokumentem.

Poznámka:

Skutečné vynucení pravidel omezení znaků se může lišit v závislosti na poskytovateli úložiště , kterého aplikace používá. Pokud chcete zajistit správné chování a kompatibilitu, postupujte podle předchozích pravidel ID instance.

ID instance orchestrace je povinný parametr pro většinu operací správy instancí. ID instancí jsou také důležitá pro diagnostiku. Použijete je například při vyhledávání dat sledování orchestrace v Application Insights pro účely řešení potíží nebo analýzy. Z tohoto důvodu uložte vygenerovaná ID instancí do externího umístění, které usnadňuje pozdější odkazování, jako je databáze nebo protokoly aplikace.

ID instance orchestrace je povinný parametr pro většinu operací správy instancí. ID instancí jsou také důležitá pro diagnostiku, takže uložte vygenerovaná ID instancí do externího umístění, které usnadňuje pozdější odkazování, jako je databáze nebo protokoly aplikace.

Spolehlivost

Funkce orchestratoru používají návrhový vzor event sourcing k zajištění spolehlivého udržování jejich stavu provádění. Místo přímého uložení aktuálního stavu orchestrace používá Durable Task Framework úložiště, do kterého lze zapisovat pouze další záznamy, k zaznamenávání úplné posloupnosti akcí, které orchestrace funkce provede. Úložiště s pouze přidáváním má v porovnání s vyprázdněním úplného stavu modulu runtime mnoho výhod. Mezi výhody patří vyšší výkon, škálovatelnost a rychlost odezvy. Získáte také konečnou konzistenci pro transakční data, úplné záznamy auditu a historii. Záznamy auditu podporují spolehlivé kompenzační akce.

Architektura Durable Task Framework transparentně používá model Event Sourcing. Funkce orchestrátoru na pozadí používá operátor await v jazyce C# a operátor yield v JavaScriptu a Pythonu. Tyto operátory vrací kontrolu nad vláknem orchestrátoru zpět k dispečeru Durable Task Framework. V Java volání .await() u úlohy předává kontrolu zpět dispečerovi prostřednictvím vlastní upravené instance Throwable. Dispečer pak uloží do úložiště všechny nové akce, které naplánuje orchestrátor. Mezi příklady akcí patří volání jedné nebo více podřízených funkcí nebo naplánování odolného časovače. Průhledná operace potvrzení aktualizuje historii vykonávání instance orchestrace přidáním všech nových událostí do úložiště, podobně jako log pouze pro přidávání. Podobně operace potvrzení vytvoří zprávy v úložišti k naplánování provedení skutečné práce. V tuto chvíli je možné funkci orchestrátoru uvolnit z paměti.

Můžete použít kteréhokoliv z dostupných poskytovatelů úložiště jako úložiště stavu za běhu.

Když funkce orchestrace zpracuje víc práce (například přijme se zpráva s odpovědí nebo vyprší platnost trvalého časovače), orchestrátor se probudí a znovu spustí celou funkci od začátku a znovu sestaví místní stav. Pokud se při přehrání kód pokusí volat funkci (nebo provést jakoukoli jinou asynchronní práci), architektura Durable Task Framework projde historii provádění aktuální orchestrace. Pokud zjistí, že aktivita již byla spuštěna a přinesla výsledek, přehraje výsledek této funkce a kód orchestrátoru se bude dál spouštět. Přehrání pokračuje, dokud se kód funkce nedokončí nebo dokud nenaplánuje novou asynchronní úlohu.

Poznámka:

Aby vzor přehrávání fungoval správně a spolehlivě, musí být kód funkce orchestrátoru deterministický. Nedeterministický kód orchestrátoru může vést k chybám za běhu nebo jinému neočekávanému chování. Další informace o omezeních kódu pro funkce orchestrátoru naleznete v tématu Omezení kódu funkce orchestratoru.

Poznámka:

Pokud funkce orchestrátoru generuje zprávy protokolu, může chování při přehrání způsobit generování duplicitních zpráv protokolu. Informace o tom, proč k tomuto chování dochází a jak ho obejít, najdete v tématu Protokolování bezpečné při opakování.

Historie orchestrace

Chování modelu Durable Task Framework při vytváření událostí je úzce spojeno s kódem funkce orchestrátoru, který napíšete. Předpokládejme, že máte funkci orchestrace řetězení aktivit, například jako následující.

Izolovaný model pracovního procesu
[Function("HelloCities")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var outputs = new List<string>();

    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

    // Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
    return outputs;
}

Model založený na třídách (izolovaný pracovník)

Přístup založený na třídách používá zdrojový generátor a vyžaduje balíček NuGet Microsoft.DurableTask.Generators .

using Microsoft.DurableTask;

[DurableTask]
public class HelloCities : TaskOrchestrator<object?, List<string>>
{
    public override async Task<List<string>> RunAsync(
        TaskOrchestrationContext context, object? input)
    {
        var outputs = new List<string>();

        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

        // Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
        return outputs;
    }
}

Model v probíhajícím procesu
[FunctionName("HelloCities")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var outputs = new List<string>();

    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

    // Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
    return outputs;
}
using Microsoft.DurableTask;

[DurableTask]
public class HelloCities : TaskOrchestrator<object?, List<string>>
{
    public override async Task<List<string>> RunAsync(TaskOrchestrationContext context, object? input)
    {
        var outputs = new List<string>();

        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

        return outputs;
    }
}

Kdykoli plánujete funkci aktivity, Durable Task Framework ukládá stav provedení funkce na různých kontrolních bodech. Na každém kontrolním bodu architektura uloží stav do trvalého úložného systému. Tento stav je historie orchestrace.

Tabulka historie

Na každém kontrolním bodě provádí Trvalý rámec úkolů následující akce:

  • Ukládá historii spuštění do trvalého úložiště.
  • Vytvoří fronty zpráv pro funkce, které orchestrátor chce vyvolat.
  • Zařadí zprávy pro samotný orchestrátor, například zprávy trvalých časovačů.

Když se dokončí kontrolní bod, framework odebere funkci orchestrátoru z paměti, dokud pro ni nebude k dispozici další práce.

Poznámka:

Azure Storage neposkytuje žádné transakční záruky ohledně konzistence dat mezi úložištěm tabulek a frontami při ukládání dat. Ke zpracování selhání používá poskytovatel Durable Functions Azure Storagevzory eventuální konzistence, například Command and Query Responsibility Segregation (CQRS). Alternativní poskytovatelé úložiště nabízejí silnější záruky konzistence:

Když se funkce zobrazená dříve dokončí, její historie vypadá podobně jako data v následující tabulce v Table Storage. Položky jsou zkráceny pro ilustraci.

PartitionKey (InstanceId) EventType Časová značka Vstup název Výsledek Stav
eaee885b ExecutionStarted 2021-05-05T18:45:28.852Z null HelloCities
eaee885b OrchestratorStarted 2021-05-05T18:45:32.362Z
eaee885b Úkol naplánován 2021-05-05T18:45:32.670Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:32.670Z
eaee885b Úkol dokončen 2021-05-05T18:45:34.201Z ""Hello Tokyo!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.232Z
eaee885b Úkol naplánován 2021-05-05T18:45:34.435Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.435Z
eaee885b Úkol dokončen 2021-05-05T18:45:34.763Z ""Hello Seattle!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.857Z
eaee885b Úkol naplánován 2021-05-05T18:45:34.857Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.857Z
eaee885b Úkol dokončen 2021-05-05T18:45:34.919Z ""Hello London!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:35.032Z
eaee885b OrchestratorCompleted 2021-05-05T18:45:35.044Z
eaee885b Dokončení provedení 2021-05-05T18:45:35.044Z "[""Hello Tokyo!"","Hello Seattle!"","Hello London!""]" Dokončeno

Sloupce tabulky obsahují následující hodnoty:

  • PartitionKey: ID instance orchestrace.
  • EventType: Typ události. Podrobné popisy všech typů událostí historie najdete v tématu Události historie architektury úlohdurable.
  • Časové razítko: Časové razítko koordinovaného univerzálního času historické události.
  • Vstup: Vstup funkce ve formátu JSON.
  • Název: Název vyvolané funkce.
  • Výsledek: Výstup funkce, konkrétně její návratová hodnota.

Výstraha

Tato tabulka je užitečná jako nástroj pro ladění, ale jeho formát a obsah se můžou při vývoji rozšíření Durable Functions změnit.

Pokaždé, když se funkce obnoví po čekání na dokončení úkolu, architektura Durable Task Framework znovu spustí funkci orchestrátoru úplně od začátku. Při každém opětovném spuštění zkontroluje historii spuštění a určí, jestli je aktuální asynchronní úloha dokončena. Pokud historie provádění ukazuje, že úloha je již dokončena, architektura přehraje výstup tohoto úkolu a přejde na další úkol. Tento proces pokračuje, dokud se nepřehraje celá historie spuštění. Po přehrání aktuální historie spuštění se místní proměnné obnoví na předchozí hodnoty.

Funkce a vzory

Následující části popisují funkce a vzory funkcí orchestrátoru.

Dílčí orchestrace v rámci funkcí orchestrátoru

Orchestrátorové funkce mohou volat funkce aktivit, ale mohou také volat jiné orchestrátorové funkce. Můžete například vytvořit větší orchestraci z knihovny funkcí orchestrátoru. Nebo můžete paralelně spustit více instancí funkce orchestrátoru.

Další informace a příklady najdete v tématu Dílčí orchestrace v Durable Functions (Azure Functions).

Trvalé časovače

Orchestrace můžou naplánovat trvalé časovače pro implementaci zpoždění nebo nastavení zpracování časového limitu u asynchronních akcí. Místo nativních jazykových rozhraní API sleep používejte ve funkcích orchestrátoru odolné časovače.

Další informace a příklady najdete v tématu Časovače v Durable Functions (Azure Functions).

Externí události

Funkce orchestratoru můžou čekat na aktualizaci instance orchestrace externími událostmi. Tato funkce Durable Functions je často užitečná pro zpracování lidských interakcí nebo jiných externích zpětných volání.

Další informace a příklady najdete v tématu Zpracování externích událostí v Durable Functions (Azure Functions).

Zpracování chyb

Funkce orchestratoru můžou používat funkce pro zpracování chyb programovacího jazyka. Orchestrační kód podporuje existující vzory jako try/catch.

Funkce orchestratoru můžou také přidávat zásady opakování do funkcí aktivity nebo dílčího orchestrátoru, které volají. Pokud aktivita nebo dílčí orchestrátor selže s výjimkou, může zadaná zásada opakování automaticky zpozdit a opakovat spuštění až do zadaného počtu opakování.

Poznámka:

Pokud je ve funkci orchestrátoru neošetřená výjimka, instance orchestrace se dokončí ve Failed stavu. Nemůžete znovu zkoušet instanci orchestrace poté, co selže.

Další informace a příklady najdete v tématu Zpracování chyb v Durable Functions (Azure Functions).

Kritické sekce (Durable Functions 2.x)

Instance orchestrace jsou jednovláknové, takže souběhové podmínky v rámci orchestrace nehrozí. Podmínky závodu jsou však možné, když orchestrace interagují s externími systémy. Pro zmírnění závodních podmínek při interakci s externími systémy mohou orchestrátorové funkce definovat kritické sekce pomocí zámku. .NET a JavaScript podporují kritické sekce.

Následující ukázkový kód ukazuje funkci orchestrátoru, která definuje kritickou část. Vstup do kritické sekce vyžaduje předání jedné nebo více odkazů trvalé entitě, která trvale spravuje stav zámku. Kód v kritické části může najednou spustit pouze jedna instance této orchestrace.

Použijte metodu LockAsync pro vstup do kritické části.

[FunctionName("Synchronize")]
public static async Task Synchronize(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var lockId = new EntityId("LockEntity", "MyLockIdentifier");
    using (await context.LockAsync(lockId))
    {
        // Critical section. Only one orchestration can enter at a time.
    }
}

V orchestracích izolovaného procesu .NET použijte TaskOrchestrationContext.Entities.LockEntitiesAsync (viz mapování rozhraní API pro izolovaný proces .NET).

Metoda LockAsync získá trvalé zámky a vrátí objekt IDisposable, který ukončí kritickou sekci při uvolnění. Tento IDisposable výsledek lze použít společně s blokem using k získání syntaktické reprezentace kritické části. Když funkce orchestrátoru zadá kritickou část, může tento blok kódu spustit pouze jedna instance. Všechny ostatní instance, které se pokusí vstoupit do kritické sekce, budou zablokované, dokud předchozí instance neukončí kritickou sekci.

Funkce kritické sekce je užitečná také pro koordinaci změn persistentních entit. Další informace o kritických sekcích najdete v Koordinace entit.

Poznámka:

Kritické sekce jsou dostupné v Durable Functions 2.x pro orchestrace .NET a JavaScript. Pro .NET se rozhraní API liší podle modelu: model v procesu používá IDurableOrchestrationContext.LockAsync, zatímco izolovaný model používá TaskOrchestrationContext.Entities.LockEntitiesAsync.

Volání koncových bodů HTTP (Durable Functions 2.x)

Orchestrátorové funkce nemohou provádět I/O operace, jak je popsáno v omezeních kódu funkcí Orchestratoru. Pro obejití tohoto omezení zabalte jakýkoli kód, který potřebuje provádět I/O operace, do funkce aktivity. Orchestrace, které komunikují s externími systémy, často používají funkce aktivit k volání PROTOKOLU HTTP a vrací výsledky do orchestrace.

Pro zjednodušení tohoto běžného modelu můžou funkce orchestrátoru tuto metodu CallHttpAsync použít k přímému vyvolání rozhraní API HTTP.

Izolovaný model pracovního procesu
[Function("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

    // Make an HTTP GET request to the specified endpoint.
    DurableHttpResponse response = await context.CallHttpAsync(
        method: HttpMethod.Get,
        uri: url,
        content: null,
        retryOptions: null);

    if ((int)response.StatusCode == 400)
    {
        // Handle error codes.
    }
}

Model v probíhajícím procesu
[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

    // Make an HTTP GET request to the specified endpoint.
    DurableHttpResponse response = 
        await context.CallHttpAsync(HttpMethod.Get, url);

    if ((int)response.StatusCode == 400)
    {
        // Handle error codes.
    }
}

Kromě podpory základních vzorů požadavků a odpovědí metoda automaticky zpracovává běžné asynchronní vzory dotazování HTTP 202. Podporuje také ověřování s externími službami pomocí spravovaných identit.

Další informace a podrobné příklady najdete v tématu Funkce HTTP.

Poznámka:

Volání koncových bodů HTTP přímo z funkcí orchestrátoru je dostupné v Durable Functions 2.0 a novějších verzích.

Předání více parametrů funkcím aktivit

Nemůžete přímo předat více parametrů funkci aktivity. Místo toho předávajte pole objektů nebo složených objektů.

Izolovaný model pracovního procesu

V .NET použijte serializovatelný složený typ, například záznam, k předání více parametrů.

public record CourseInfo(string Major, int UniversityYear);

[Function("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    int universityYear = context.GetInput<int>();
    CourseInfo courseInfo = new("ComputerScience", universityYear);
    object courseRecommendations = await context.CallActivityAsync<object>(
        "CourseRecommendations", courseInfo);
    return courseRecommendations;
}

Model v probíhajícím procesu

V .NET použijte serializovatelný složený typ pro předání více parametrů. Následující ukázka používá jednoduchou třídu:

public class CourseInfo
{
    public string Major { get; set; }
    public int UniversityYear { get; set; }
}

[FunctionName("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var input = new CourseInfo
    {
        Major = "ComputerScience",
        UniversityYear = context.GetInput<int>()
    };

    object courseRecommendations = await context.CallActivityAsync<object>(
        "CourseRecommendations",
        input);
    return courseRecommendations;
}

V .NET se používají typy záznamů nebo n-tice k předávání více parametrů jako jednoho složeného objektu.

using Microsoft.DurableTask;

public record LocationInfo(string City, string State);

[DurableTask]
public class GetWeatherOrchestration : TaskOrchestrator<object?, string>
{
    public override async Task<string> RunAsync(TaskOrchestrationContext context, object? input)
    {
        var location = new LocationInfo("Seattle", "WA");
        string weather = await context.CallActivityAsync<string>("GetWeather", location);
        return weather;
    }
}

Další kroky