Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Vytvářejte stavové aplikace pomocí Durable Functions. Jedná se o rozšíření Azure Functions. Pro koordinaci dalších funkcí Durable ve vaší aplikaci použijte funkci orchestrator. Funkce orchestratoru jsou stavové, spolehlivé a jsou vytvořené tak, aby běžely dlouhou dobu.
Vytvářejte stavové pracovní postupy odolné chybám pomocí sad Durable Task SDKs v .NET, Python a Java. Orchestrator slouží ke koordinaci aktivit a dílčích orchestrací. Orchestrátory jsou stavové, spolehlivé a jsou vytvořené tak, aby běžely dlouhou dobu.
Omezení kódu orchestrátoru
Funkce orchestrátoru používají event sourcing k zajištění spolehlivého provádění a zachování stavu místních proměnných. Chování přehrání kódu orchestrátoru vytváří omezení pro typ kódu, který můžete psát ve funkci orchestrátoru. Funkce orchestrátoru musí být například deterministické: funkce orchestrátoru se několikrát přehraje a pokaždé musí vytvořit stejný výsledek.
Orchestrátory používají model Event Sourcing k zajištění spolehlivého spouštění a udržování stavu místních proměnných. Fungování přehrávání kódu orchestrátoru vytváří omezení na typ kódu, který můžete psát. Například orchestrátory musí být deterministické: orchestrátor se musí několikrát opakovat a pokaždé musí dosáhnout stejného výsledku.
Použití deterministických rozhraní API
Tady je několik jednoduchých pokynů, které vám pomůžou zajistit, aby byl váš kód deterministický.
Používejte rozhraní API z cílových jazyků v rámci funkcí orchestrátoru, ale pouze deterministická rozhraní API. Deterministické rozhraní API vždy vrací stejnou hodnotu pro stejný vstup bez ohledu na to, kdy nebo jak často se volá.
Následující části obsahují pokyny k rozhraním API a vzorům, kterým byste se měli vyhnout, protože nejsou deterministické. Tato omezení platí jenom pro funkce orchestrátoru. Jiné typy funkcí nemají taková omezení.
Tady je několik jednoduchých pokynů, které vám pomůžou zajistit, aby byl váš kód deterministický.
Volejte rozhraní API z cílových jazyků v orchestrátorech, ale používejte pouze deterministická rozhraní API. Deterministické rozhraní API vždy vrací stejnou hodnotu pro stejný vstup bez ohledu na to, kdy nebo jak často se volá.
Následující části obsahují pokyny k rozhraním API a vzorům, kterým byste se měli vyhnout, protože nejsou deterministické. Tato omezení platí pouze pro orchestrátory. Aktivity nemají taková omezení.
Poznámka:
Tento článek se zabývá běžnými omezeními kódu orchestrátoru, ale není vyčerpávající. Zaměřte se na to, jestli je rozhraní API deterministické. S tímto myšlením obvykle můžete zjistit, která rozhraní API se dají bezpečně používat bez odkazu na tento seznam.
Datum a čas
Rozhraní API založená na čase jsou neurčitá a nikdy by se neměla používat ve funkcích orchestrátoru. Každé přehrání funkce orchestrátoru generuje jinou hodnotu. Místo toho použijte alternativní rozhraní API Durable Functions pro získání aktuálního data a času, které zůstává konzistentní během přehrávání.
Nepoužívejte DateTime.Now, DateTime.UtcNow ani ekvivalentní rozhraní API k získání aktuálního času. Třídám, jako je Stopwatch, by se mělo také vyhnout. Pro .NET funkce orchestratoru v procesu použijte vlastnost IDurableOrchestrationContext.CurrentUtcDateTime k získání aktuálního času. Pro .NET izolované funkce orchestrátoru použijte vlastnost TaskOrchestrationContext.CurrentDateTimeUtc k získání aktuálního času.
DateTime startTime = context.CurrentUtcDateTime;
// do some work
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);
Rozhraní API založená na čase jsou nedeterministická a nikdy by se neměla používat v orchestrátorech. Každé přehrání orchestrátoru generuje jinou hodnotu. Místo toho použijte ekvivalentní rozhraní API sady Durable Task SDK k získání aktuálního data nebo času, které zůstává konzistentní napříč přehráváními.
Nepoužívejte DateTime.Now, DateTime.UtcNow ani ekvivalentní rozhraní API k získání aktuálního času. Třídám, jako je Stopwatch, by se mělo také vyhnout.
TaskOrchestrationContext.CurrentUtcDateTime Pomocí vlastnosti získáte aktuální čas.
using Microsoft.DurableTask;
public class TimerExample : TaskOrchestrator<object?, TimeSpan>
{
public override async Task<TimeSpan> RunAsync(TaskOrchestrationContext context, object? input)
{
// Use context.CurrentUtcDateTime instead of DateTime.Now or DateTime.UtcNow
DateTime startTime = context.CurrentUtcDateTime;
// do some work
await context.CallActivityAsync("DoWork", null);
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);
return totalTime;
}
}
Identifikátory GUID a identifikátory UUID
Rozhraní API, která vracejí náhodný identifikátor GUID nebo UUID, jsou nedeterministické, protože vygenerovaná hodnota se pro každé přehrání liší. V závislosti na vašem jazyce může být k dispozici integrované rozhraní API pro generování deterministických identifikátorů GUID nebo identifikátorů UUID. V opačném případě použijte funkci aktivity k vrácení náhodně generovaného identifikátoru GUID nebo UUID.
Místo rozhraní API, jako je Guid.NewGuid(), použijte rozhraní API pro kontextový objekt NewGuid() k vygenerování náhodného GUID, který je bezpečný pro přehrání orchestrátoru.
Guid randomGuid = context.NewGuid();
Poznámka:
Identifikátory GUID vygenerované pomocí rozhraní API kontextu orchestrace jsou identifikátory UUID typu 5.
Rozhraní API, která vracejí náhodný identifikátor GUID nebo UUID, jsou nedeterministické, protože vygenerovaná hodnota se pro každé přehrání liší. V závislosti na vašem jazyce může být k dispozici integrované rozhraní API pro generování deterministických identifikátorů GUID nebo identifikátorů UUID. V opačném případě použijte aktivitu k vrácení náhodně generovaného identifikátoru GUID nebo UUID.
Místo rozhraní API, jako je Guid.NewGuid(), použijte rozhraní API pro kontextový objekt NewGuid() k vygenerování náhodného GUID, který je bezpečný pro přehrání orchestrátoru.
using Microsoft.DurableTask;
public class GuidExample : TaskOrchestrator<object?, Guid>
{
public override async Task<Guid> RunAsync(TaskOrchestrationContext context, object? input)
{
// Use context.NewGuid() instead of Guid.NewGuid()
Guid randomGuid = context.NewGuid();
return randomGuid;
}
}
Poznámka:
Identifikátory GUID vygenerované pomocí rozhraní API kontextu orchestrace jsou identifikátory UUID typu 5.
Náhodná čísla
Použijte funkci aktivity k vrácení náhodných čísel do funkce orchestrátoru. Návratové hodnoty funkcí aktivit jsou vždy bezpečné pro přehrání, protože se ukládají do historie orchestrace.
Alternativně můžete použít generátor náhodných čísel s pevnou počáteční hodnotou přímo ve funkci orchestrátoru. Tento přístup je bezpečný, pokud se pro každé přehrání orchestrace vygeneruje stejná posloupnost čísel.
Aktivita slouží k vrácení náhodných čísel do orchestrátoru. Hodnoty vrácené aktivitami jsou vždy bezpečné pro opětovné přehrání, protože jsou uloženy v historii orchestrace.
Alternativně můžete použít generátor náhodných čísel s pevnou počáteční hodnotou přímo v orchestrátoru. Tento přístup je bezpečný, pokud se pro každé přehrání orchestrace vygeneruje stejná posloupnost čísel.
Propojení
Nepoužívejte vazby ve funkci orchestrátoru, včetně vazeb klienta orchestrace a klienta entity . Vstupní a výstupní vazby používejte pouze ve funkci klienta nebo aktivity. Funkce orchestratoru se můžou přehrávat vícekrát, což způsobuje nedeterministické a duplicitní vstupně-výstupní operace s externími systémy.
Orchestrátory by neměly provádět přímé vstupně-výstupní operace s externími systémy. Přesunutí vstupně-výstupních operací do aktivit Orchestrátory mohou provádět opakované operace, což způsobuje nedeterministické a duplicitní vstupně-výstupní operace s externími systémy.
Statické proměnné
Statické proměnné se můžou v průběhu času měnit a znepřístupnit tak funkcím orchestrátoru. Nepoužívejte statické proměnné ve funkcích orchestrátoru, protože jejich hodnoty se můžou v průběhu času měnit, což vede k nedeterministickému chování modulu runtime. Místo toho používejte konstanty nebo omezte použití statických proměnných na funkce aktivit.
Statické proměnné se můžou v průběhu času měnit, což je pro orchestrátory nebezpečné. Vyhněte se použití statických proměnných v orchestrátorech, protože jejich hodnoty se můžou v průběhu času měnit, což vede k nedeterministickému chování modulu runtime. Místo toho používejte konstanty nebo omezte používání statických proměnných na aktivity.
Poznámka:
I mimo funkce orchestrátoru může být používání statických proměnných v Azure Functions problematické z různých důvodů, protože neexistuje žádná záruka, že statický stav přetrvává napříč několika prováděními funkcí. Vyhněte se statickým proměnným s výjimkou specifických případů použití, jako je například in-memory caching na bázi nejlepšího úsilí ve funkcích aktivit a entit.
Proměnné prostředí
Proměnné prostředí ve funkcích orchestrátoru se můžou v průběhu času měnit, což vede k nedeterministickému chování modulu runtime. Pokud funkce orchestrátoru potřebuje konfiguraci definovanou v proměnné prostředí, musíte předat konfigurační hodnotu do funkce orchestrátoru jako vstup nebo jako návratovou hodnotu funkce aktivity.
Proměnné prostředí v orchestrátorech se můžou v průběhu času měnit, což vede k nedeterministickému chování modulu runtime. Pokud orchestrátor potřebuje konfiguraci definovanou v proměnné prostředí, musíte předat hodnotu konfigurace orchestrátoru jako vstup nebo jako návratovou hodnotu aktivity.
Síť a HTTP
Funkce aktivit slouží k odchozím síťovým voláním. Pokud potřebujete provést volání HTTP z funkce orchestrátoru, můžete také použít odolná rozhraní HTTP API.
Aktivity použijte k provádění odchozích síťových volání. Orchestrátory by nikdy neměly provádět přímá volání HTTP ani jiné síťové požadavky, protože tyto operace nejsou neurčité.
Rozhraní API blokující vlákna
Blokování rozhraní API, jako je sleep, může způsobit problémy s výkonem a škálováním funkcí orchestrátoru a může vést k zbytečným poplatkům za dobu provádění v plánu Azure Functions Consumption. Pokud jsou k dispozici, použijte alternativy. Pomocí trvalých časovačů můžete například vytvořit zpoždění, která jsou bezpečná pro přehrání a nezapočítávají se do doby provádění orchestrátoru.
Blokování rozhraní API, jako je "sleep", může způsobit problémy s výkonem a škálováním orchestrátorů a mělo by se jim vyhnout. Pomocí trvalých časovačů můžete vytvářet zpoždění, která jsou bezpečná pro přehrání.
Použijte context.CreateTimer() místo Task.Delay() nebo Thread.Sleep().
// Don't use Task.Delay() or Thread.Sleep()
// Use context.CreateTimer() instead
await context.CreateTimer(context.CurrentUtcDateTime.AddMinutes(5), CancellationToken.None);
Asynchronní rozhraní API
Kód orchestratoru nesmí nikdy spustit žádnou asynchronní operaci, s výjimkou operací definovaných kontextovým objektem triggeru orchestrace. Například nikdy nepoužívejte Task.Run, Task.Delay a HttpClient.SendAsync v .NET nebo setTimeout a setInterval v JavaScriptu. Funkce orchestrátoru by měla plánovat pouze asynchronní práci pomocí rozhraní API Durable SDK, jako jsou funkce plánování aktivit. Všechny ostatní typy asynchronních volání by se měly provádět uvnitř funkcí aktivit.
Kód orchestrátoru nesmí nikdy spustit žádnou asynchronní operaci, s výjimkou operací definovaných objektem kontextu orchestrace. Například nikdy nepoužívejte Task.Run, Task.Delay a HttpClient.SendAsync v .NET. Orchestrátor by měl plánovat pouze asynchronní práci pomocí rozhraní API sady Durable Task SDK, jako jsou aktivity plánování. Všechny ostatní typy asynchronních vyvolání by se měly provádět uvnitř aktivit.
Asynchronní javascriptové funkce
Deklarujte funkce orchestrátoru JavaScriptu jako synchronní generátorové funkce. Neeklarujte funkce orchestrátoru JavaScriptu jako async, protože modul runtime Node.js nezaručuje deterministické chování pro funkce typu async.
Python coroutiny
Nedefinujte funkce orchestrátoru v Pythonu jako korutiny. Nepoužívejte klíčové slovo async, protože korutinová sémantika není v souladu s modelem přehrávání Durable Functions. Deklarujte funkce orchestrátoru Python jako generátory a použijte yield místo await s rozhraním API context.
Nesmíte deklarovat Python orchestrátory jako korutiny. Jinými slovy, nikdy nedeklarujte Python orchestrátory pomocí klíčového slova async, protože sémantika korutin není v souladu s modelem přehrávání v rámci trvalých úloh. Orchestrátory Python musíte vždy deklarovat jako generátory, což znamená, že při volání kontextových rozhraní API byste měli místo yield použít await.
from durabletask import task
# CORRECT - use yield (generator function)
def my_orchestrator(ctx: task.OrchestrationContext, input: str):
result = yield ctx.call_activity(my_activity, input=input)
return result
# WRONG - don't use async/await
async def bad_orchestrator(ctx: task.OrchestrationContext, input: str):
result = await ctx.call_activity(my_activity, input=input) # This won't work!
return result
rozhraní API pro .NET vláken
Durable Task Framework spouští kód orchestrátoru na jednom vlákně a nemůže pracovat s žádnými dalšími vlákny. Spuštění asynchronní pokračování na vláknu pracovní skupiny v rámci vykonávání orchestrace může vést k nedeterministickému provedení nebo zablokování. Z tohoto důvodu by funkce orchestrátoru neměly téměř nikdy používat API vláken. Například nikdy nepoužívejte ConfigureAwait(continueOnCapturedContext: false) ve funkci orchestrátoru, aby se zajistilo, že pokračování úloh běží na původní SynchronizationContextfunkci orchestrátoru .
Poznámka:
Durable Task Framework se pokouší detekovat náhodné použití vláken nonorchestrator ve funkcích orchestrátoru. Pokud najde porušení, framework vyvolá výjimku NonDeterministicOrchestrationException. Toto chování detekce ale nezachytí všechna porušení a neměli byste na něm záviset.
Durable Task Framework spouští kód orchestrátoru na jednom vlákně a nemůže pracovat s žádnými dalšími vlákny. Spuštění asynchronní pokračování na vláknu pracovní skupiny v rámci vykonávání orchestrace může vést k nedeterministickému provedení nebo zablokování. Z tohoto důvodu by orchestrátory neměly téměř nikdy používat rozhraní API pro dělení na vlákna. Například nikdy nepoužívejte ConfigureAwait(continueOnCapturedContext: false) v orchestrátoru k zajištění, že pokračování úloh poběží na původním SynchronizationContextorchestrátoru.
Poznámka:
Durable Task Framework se pokouší zjistit náhodné použití neorchestračních vláken v orchestrátorech. Pokud najde porušení, framework vyvolá výjimku NonDeterministicOrchestrationException. Toto chování detekce ale nezachytí všechna porušení a neměli byste na něm záviset.
Verzování
Trvalá orchestrace může běžet po dny, měsíce, roky nebo dokonce jako věčná orchestrace. Změny kódu, které ovlivňují spouštění orchestrací, můžou přerušit chování přehrávání, takže před aktualizací aplikace pečlivě naplánujte. Další informace najdete v tématu Správa verzí.
Trvalá orchestrace může běžet dny, měsíce, roky nebo dokonce neomezeně dlouho. Změny kódu, které ovlivňují spouštění orchestrací, můžou přerušit chování přehrávání, takže před aktualizací aplikace pečlivě naplánujte. Mezi běžné strategie správy verzí patří souběžné nasazení a použití názvů centra úloh specifických pro verzi.
Trvalé úlohy
Poznámka:
Tato část popisuje interní podrobnosti implementace Durable Task Framework. Abyste mohli používat Durable Functions, nemusíte tyto informace znát, ale pomůže vám to vysvětlit chování přehrávání.
Úlohy, které mohou bezpečně čekat v rámci funkcí orchestrátoru, se někdy nazývají odolné úlohy. Durable Task Framework vytváří a spravuje tyto úlohy. Mezi příklady patří úlohy vrácené funkcí CallActivityAsync, WaitForExternalEvent a CreateTimer ve funkcích orchestrátoru .NET.
Seznam objektů TaskCompletionSource v .NET spravuje tyto trvalé úlohy interně. Kód orchestrátoru vytvoří tyto úlohy během přehrání. Dispečer je dokončí, zatímco vyjmenovává odpovídající události historie.
Modul runtime provede úlohy synchronně na jednom vlákně, dokud nepřehraje historii. Pokud se trvalý úkol nedokončí do konce přehrávání historie, modul runtime provede příslušné akce. Modul runtime může například vytvořit frontu zprávy pro volání funkce aktivity.
Toto chování běhového prostředí vysvětluje, proč funkce orchestrátoru nemůže použít await nebo yield v netrvalé úloze. Vlákno dispečera nemůže čekat na dokončení úlohy a zpětná volání z této úlohy mohou narušit stav sledování funkce orchestrátoru. Modul runtime obsahuje kontroly, které vám pomůžou tyto porušení rozpoznat.
Další informace o tom, jak Durable Task Framework spouští funkce orchestrátoru, najdete ve zdrojovém kódu úlohy Durable Task na GitHub. Zejména viz TaskOrchestrationExecutor.cs a TaskOrchestrationContext.cs.
Úlohy, které můžou bezpečně čekat v orchestrátorech, se někdy nazývají perzistentní úlohy. Durable Task Framework vytváří a spravuje tyto úlohy. Mezi příklady patří úlohy vrácené CallActivityAsync, WaitForExternalEvent a CreateTimer v orchestrátorech .NET.
Seznam objektů TaskCompletionSource v .NET spravuje tyto trvalé úlohy interně. Kód orchestrátoru vytvoří tyto úlohy během přehrání. Dispečer je dokončí, zatímco vyjmenovává odpovídající události historie.
Modul runtime provede úlohy synchronně na jednom vlákně, dokud nepřehraje historii. Pokud se trvalý úkol nedokončí do konce přehrávání historie, modul runtime provede příslušné akce. Modul runtime může například vytvořit frontu zprávy pro volání aktivity.
Toto chování modulu runtime vysvětluje, proč orchestrátor nemůže použít await nebo yield v neperzistentní úloze. Vlákno dispečeru nemůže čekat na dokončení úlohy a zpětné volání z této úlohy může poškodit stav sledování orchestrátoru. Modul runtime obsahuje kontroly, které vám pomůžou tyto porušení rozpoznat.
Další informace o tom, jak Durable Task Framework spouští orchestrátory, najdete ve zdrojovém kódu Durable Task na GitHubu. Zejména viz TaskOrchestrationExecutor.cs a TaskOrchestrationContext.cs.