Trvalé orchestrace

Durable Functions je rozšíření azure Functions. Funkci orchestrátoru můžete použít k orchestraci provádění dalších durable funkcí v aplikaci funkcí. Funkce orchestrátoru mají následující charakteristiky:

  • Funkce orchestratoru definují pracovní postupy funkcí pomocí procedurálního kódu. Nejsou potřeba žádná deklarativní schémata ani návrháři.
  • Funkce orchestratoru můžou volat další odolné funkce synchronně a asynchronně. Výstup z volaných funkcí lze spolehlivě uložit do místních proměnných.
  • Funkce orchestratoru jsou odolné a spolehlivé. Průběh provádění se automaticky zkontroluje, když funkce "awaits" nebo "yields" (výnosy). Při recyklaci procesu nebo restartování virtuálního počítače se nikdy neztratí místní stav.
  • Funkce orchestratoru můžou být dlouhotrvající. Celková životnost instance orchestrace může být sekundy, dny, měsíce nebo nikdy nekončící.

Tento článek obsahuje přehled funkcí orchestrátoru a jejich pomoc při řešení různých problémů s vývojem aplikací. Pokud ještě neznáte typy funkcí, které jsou k dispozici v aplikaci Durable Functions, přečtěte si nejprve článek o typech durable functions.

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ý identifikátor GUID. ID instancí ale můžou být také libovolná hodnota řetězce vygenerovaná uživatelem. Každé ID instance orchestrace musí být jedinečné v rámci centra úloh.

Tady jsou některá pravidla týkající se ID instancí:

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

Poznámka:

Obecně se doporučuje používat id automaticky vygenerovaných instancí, kdykoli je to možné. ID instancí generovaných uživatelem jsou určená pro scénáře, kdy existuje mapování 1:1 mezi instancí orchestrace a určitou entitou specifickou pro externí aplikaci, jako je nákupní objednávka nebo dokument.

Skutečné vynucení pravidel omezení znaků se také 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, důrazně doporučujeme dodržovat pravidla ID instance uvedená dříve.

ID instance orchestrace je povinný parametr pro většinu operací správy instancí. Jsou také důležité pro diagnostiku, jako je vyhledávání dat sledování orchestrace v aplikaci Přehledy pro účely řešení potíží nebo analýzy. Z tohoto důvodu doporučujeme uložit vygenerovaná ID instancí do některého externího umístění (například do databáze nebo v protokolech aplikace), kde je můžete později snadno odkazovat.

Spolehlivost

Funkce orchestratoru spolehlivě udržují stav provádění pomocí vzoru návrhu event sourcingu . Místo přímého uložení aktuálního stavu orchestrace používá Durable Task Framework úložiště jen pro připojení k zaznamenání celé řady akcí, které orchestrace funkce provede. Úložiště jen pro připojení má v porovnání s "dumpingem" úplný stav 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 a úplné záznamy auditu a historii. Záznamy auditu podporují spolehlivé kompenzační akce.

Durable Functions transparentně používá model Event Sourcing. Operátor await (C#) nebo yield (JavaScript/Python) ve funkci orchestrátoru na pozadí poskytuje kontrolu nad vláknem orchestrátoru zpět k dispečeru Durable Task Framework. V případě Javy neexistuje žádné speciální klíčové slovo jazyka. Místo toho volání .await() úkolu vrátí řízení zpět dispečeru prostřednictvím vlastního Throwable. Dispečer pak potvrdí do úložiště všechny nové akce, na které je naplánovaná funkce orchestrátoru (například volání jedné nebo více podřízených funkcí nebo plánování odolného časovače). Akce transparentního potvrzení aktualizuje historii provádění instance orchestrace připojením všech nových událostí do úložiště, podobně jako protokol jen pro připojení. Podobně akce potvrzení vytvoří zprávy v úložišti pro naplánování skutečné práce. V tuto chvíli je možné funkci orchestrátoru uvolnit z paměti. Durable Functions ve výchozím nastavení používá Azure Storage jako úložiště stavu modulu runtime, ale podporují se také další poskytovatelé úložiště.

Když má funkce orchestrace více práce (například přijme se zpráva odpovědi nebo vyprší trvalý časovač), 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 jinou asynchronní práci), architektura Durable Task Framework projde historii provádění aktuální orchestrace. Pokud zjistí, že se funkce aktivity už spustila 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í práci.

Poznámka:

Aby vzor přehrávání fungoval správně a spolehlivě, musí být kód funkce orchestrátoru deterministický. Ne deterministický 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 najdete v dokumentaci k omezením kódu funkce orchestrátoru.

Poznámka:

Pokud funkce orchestrátoru generuje zprávy protokolu, může chování při přehrání způsobit, že se vygenerují duplicitní zprávy protokolu. Další informace o tom, proč k tomuto chování dochází a jak s ním pracovat, najdete v tématu Protokolová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 orchestratoru řetězení aktivit, například následující funkci orchestrátoru:

Poznámka:

Verze 4 programovacího modelu Node.js pro Azure Functions je obecně dostupná. Nový model v4 je navržený tak, aby měl flexibilnější a intuitivnější prostředí pro vývojáře v JavaScriptu a TypeScriptu. Další informace o rozdílech mezi v3 a v4 najdete v průvodci migrací.

V následujících fragmentech kódu JavaScript (PM4) označuje programovací model V4, nové prostředí.

[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"));

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

Pokaždé, když je naplánovaná funkce aktivity, kontrolní bod architektury Durable Task Framework zkontroluje stav spuštění funkce do některého back-endu odolného úložiště (ve výchozím nastavení Azure Table Storage). Tento stav se označuje jako historie orchestrace.

Tabulka historie

Obecně řečeno, Durable Task Framework dělá na každém kontrolním bodu následující:

  1. Uloží historii spouštění do odolného úložiště.
  2. Vytvoří fronty zpráv pro funkce, které orchestrátor chce vyvolat.
  3. Zařadí zprávy pro samotný orchestrátor – například zprávy trvalých časovačů.

Po dokončení kontrolního bodu je funkce orchestrátoru zdarma odebrána z paměti, dokud nebude k dispozici více práce.

Poznámka:

Azure Storage neposkytuje žádné transakční záruky mezi ukládáním dat do úložiště tabulek a frontami. Aby bylo možné zpracovávat chyby, poskytovatel služby Durable Functions Azure Storage používá vzory konečné konzistence . Tyto vzory zajišťují, že v případě chybového ukončení nebo ztráty připojení uprostřed kontrolního bodu nedojde ke ztrátě dat. Alternativní poskytovatelé úložiště, jako je poskytovatel úložiště Durable Functions MSSQL, můžou poskytovat silnější záruky konzistence.

Po dokončení vypadá historie dříve zobrazené funkce přibližně jako následující tabulka ve službě Azure Table Storage (zkrácená pro účely ilustrace):

PartitionKey (InstanceId) Typ události Časové razítko 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 TaskScheduled 2021-05-05T18:45:32.670Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:32.670Z
eaee885b TaskCompleted 2021-05-05T18:45:34.201Z ""Hello Tokyo!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.232Z
eaee885b TaskScheduled 2021-05-05T18:45:34.435Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.435Z
eaee885b TaskCompleted 2021-05-05T18:45:34.763Z ""Hello Seattle!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.857Z
eaee885b TaskScheduled 2021-05-05T18:45:34.857Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.857Z
eaee885b TaskCompleted 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 ExecutionCompleted 2021-05-05T18:45:35.044Z "[""Hello Tokyo!"","Hello Seattle!"","Hello London!""]" Dokončeno

Několik poznámek k hodnotám sloupců:

  • PartitionKey: Obsahuje ID instance orchestrace.
  • EventType: Představuje typ události. Podrobné popisy všech typů událostí historie najdete tady.
  • Časové razítko: Časové razítko UTC události historie.
  • Název: Název funkce, která byla vyvolána.
  • Vstup: Vstup ve formátu JSON funkce.
  • Výsledek: Výstup funkce, tj. její návratová hodnota.

Upozorňující

I když je užitečný jako nástroj pro ladění, nepřebíjejte žádnou závislost na této tabulce. S vývojem rozšíření Durable Functions se může změnit.

Pokaždé, když je funkce obnovena po čekání na dokončení úkolu, aplikace 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 se aktuální asynchronní úloha dokončila. Pokud historie provádění ukazuje, že úloha již byla dokončena, architektura přehraje výstup tohoto úkolu a přejde k dalšímu úkolu. 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

Další části popisují funkce a vzory funkcí orchestrátoru.

Dílčí orchestrace

Funkce orchestratoru můžou volat funkce aktivit, ale také jiné funkce orchestrátoru. 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 článku Dílčí orchestrace .

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í. V funkcích orchestrátoru používejte trvalé časovače místo rozhraní API pro režim spánku nativní pro jazyk.

Další informace a příklady naleznete v článku Trvalé časovače .

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é interakce nebo jiných externích zpětného volání.

Další informace a příklady najdete v článku o externích událostech .

Zpracování chyb

Funkce orchestratoru můžou používat funkce pro zpracování chyb programovacího jazyka. Existující vzory, jako try/catch jsou podporované v kódu orchestrace.

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. Instanci orchestrace nelze opakovat, jakmile selhala.

Další informace a příklady najdete v článku Zpracování chyb.

Kritické oddíly (Durable Functions 2.x, aktuálně pouze .NET)

Instance orchestrace jsou jednovláknové, takže se nemusíte starat o podmínky časování v rámci orchestrace. Podmínky časování jsou však možné, když orchestrace komunikují s externími systémy. Kvůli zmírnění podmínek časování při interakci s externími systémy můžou funkce orchestrátoru LockAsync definovat kritické oddíly pomocí metody v .NET.

Následující ukázkový kód ukazuje funkci orchestrátoru, která definuje kritickou část. Pomocí metody zadá kritickou LockAsync část. Tato metoda vyžaduje předání jednoho nebo více odkazů na Durable Entity, která trvale spravuje stav zámku. Kód v kritické části může najednou spustit pouze jedna instance této orchestrace.

[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
    }
}

Získá LockAsync trvalé zámky a vrátí ten IDisposable , který ukončí kritickou část při vyřazení. 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í zadat kritický oddíl, se zablokují, dokud předchozí instance nezavře kritickou část.

Funkce kritického oddílu je užitečná také pro koordinaci změn trvalých entit. Další informace o důležitých oddílech najdete v tématu "Koordinace entit" .

Poznámka:

Kritické části jsou k dispozici v Durable Functions 2.0. V současné době tuto funkci implementují pouze orchestrace v .NET. Entity a kritické oddíly zatím nejsou v Durable Functions k dispozici pro pracovní proces izolovaný dotnet.

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

Funkce orchestratoru nemají povolené vstupně-výstupní operace, jak je popsáno v omezeních kódu funkce orchestrátoru. Typickým alternativním řešením tohoto omezení je zabalit veškerý kód, který musí provádět vstupně-výstupní operace ve funkci aktivity. Orchestrace, které komunikují s externími systémy, často používají funkce aktivit k volání HTTP a vrací výsledek do orchestrace.

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

[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

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

    if ((int)response.StatusCode == 400)
    {
        // handling of error codes goes here
    }
}

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

Další informace a podrobné příklady najdete v článku o funkcích HTTP.

Poznámka:

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

Předávání více parametrů

Funkci aktivity není možné předat přímo více parametrů. Doporučuje se předat pole objektů nebo složených objektů.

V rozhraní .NET můžete také použít objekty ValueTuple . Následující ukázka používá nové funkce ValueTuple přidané v jazyce C# 7:

[FunctionName("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string major = "ComputerScience";
    int universityYear = context.GetInput<int>();

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

[FunctionName("CourseRecommendations")]
public static async Task<object> Mapper([ActivityTrigger] IDurableActivityContext inputs)
{
    // parse input for student's major and year in university
    (string Major, int UniversityYear) studentInfo = inputs.GetInput<(string, int)>();

    // retrieve and return course recommendations by major and university year
    return new
    {
        major = studentInfo.Major,
        universityYear = studentInfo.UniversityYear,
        recommendedCourses = new []
        {
            "Introduction to .NET Programming",
            "Introduction to Linux",
            "Becoming an Entrepreneur"
        }
    };
}

Další kroky