Omezení kódu funkce Orchestratoru
Durable Functions je rozšíření Azure Functions, které umožňuje vytvářet stavové aplikace. Funkci orchestrátoru můžete použít k orchestraci provádění dalších trvalých funkcí v rámci aplikace funkcí. Funkce orchestratoru jsou stavové, spolehlivé a potenciálně dlouhotrvající.
Omezení kódu orchestrátoru
Funkce nástroje Orchestrator používají event sourcing k zajištění spolehlivého provádění a k udržování stavu místní proměnné. Chování přehrání kódu orchestrátoru vytváří omezení typu kódu, který můžete napsat ve funkci orchestrátoru. Například funkce orchestrátoru musí být deterministické: funkce orchestrátoru se přehraje několikrát a pokaždé musí mít stejný výsledek.
Použití deterministických rozhraní API
Tato část obsahuje několik jednoduchých pokynů, které vám pomůžou zajistit deterministický kód.
Funkce orchestratoru můžou volat libovolné rozhraní API ve svých cílových jazycích. Je však důležité, aby funkce orchestrátoru volaly pouze deterministická rozhraní API. Deterministické rozhraní API je rozhraní API, které vždy vrací stejnou hodnotu se stejným vstupem 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í se vztahují pouze na funkce orchestrátoru. Jiné typy funkcí taková omezení nemají.
Poznámka
Několik typů omezení kódu je popsáno níže. Tento seznam bohužel není vyčerpávající a některé případy použití nemusí být pokryté. Nejdůležitější věcí, kterou je potřeba při psaní kódu orchestrátoru zvážit, je, jestli je rozhraní API, které používáte, deterministické. Jakmile budete s tímto způsobem přemýšlet, snadno pochopíte, která rozhraní API se bezpečně používají a která ne, aniž byste museli odkazovat na tento zdokumentovaný seznam.
Data a časy
Rozhraní API, která vracejí aktuální datum nebo čas, nejsou určená a nikdy by se neměla používat ve funkcích orchestrátoru. Je to proto, že každé přehrání funkce orchestrátoru vytvoří jinou hodnotu. Místo toho byste měli k získání aktuálního data nebo času použít Durable Functions ekvivalentní rozhraní API, které zůstává konzistentní napříč přehráváními.
Pro získání aktuálního času nepoužívejte DateTime.Now
DateTime.UtcNow
, ani ekvivalentní rozhraní API. Takovým třídám Stopwatch
byste se také měli vyhnout. Pro funkce orchestrátoru v procesu .NET použijte k získání aktuálního IDurableOrchestrationContext.CurrentUtcDateTime
času vlastnost . U izolovaných funkcí orchestrátoru .NET použijte k získání aktuálního TaskOrchestrationContext.CurrentDateTimeUtc
času vlastnost .
DateTime startTime = context.CurrentUtcDateTime;
// do some work
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);
Identifikátory GUID a UUID
Rozhraní API, která vracejí náhodný identifikátor GUID nebo UUID, nejsou deterministická, protože vygenerovaná hodnota se pro každé přehrání liší. V závislosti na tom, který jazyk používáte, může být k dispozici integrované rozhraní API pro generování deterministických identifikátorů GUID nebo UUID. V opačném případě použijte funkci aktivity k vrácení náhodně vygenerovaného identifikátoru GUID nebo UUID.
Nepoužívejte rozhraní API, jako Guid.NewGuid()
je generování náhodných identifikátorů GUID. Místo toho použijte rozhraní API kontextového NewGuid()
objektu k vygenerování náhodného identifikátoru GUID, který je bezpečný pro přehrání orchestrátoru.
Guid randomGuid = context.NewGuid();
Poznámka
Identifikátory GUID generované pomocí rozhraní API kontextu orchestrace jsou identifikátory UUID typu 5.
Náhodná čísla
Funkce aktivity slouží k vrácení náhodných čísel do funkce orchestrátoru. Návratové hodnoty funkcí aktivity jsou vždy bezpečné pro přehrání, protože se ukládají do historie orchestrace.
Případně lze generátor náhodných čísel s pevnou počáteční hodnotou použít 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.
Vazby
Funkce orchestrátoru nesmí používat žádné vazby, včetně klientských vazeb orchestrace a entit . Vždy používejte vstupní a výstupní vazby z klienta nebo funkce aktivity. To je důležité, protože funkce orchestrátoru se můžou přehrávat několikrát, což u externích systémů způsobuje nedeterministické a duplicitní vstupně-výstupní operace.
Statické proměnné
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žijte konstanty nebo omezte použití statických proměnných na funkce aktivit.
Poznámka
Používání statických proměnných v Azure Functions může být problematické z různých důvodů i mimo funkce orchestrátoru, protože neexistuje žádná záruka, že statický stav bude při provádění více funkcí přetrvávat. Statickým proměnným byste se měli vyhnout s výjimkou velmi specifických případů použití, jako je ukládání do mezipaměti v paměti s maximálním úsilím ve funkcích aktivit nebo entit.
Proměnné prostředí
Nepoužívejte proměnné prostředí ve funkcích orchestrátoru. Jejich hodnoty 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, která je definovaná v proměnné prostředí, musíte předat hodnotu konfigurace do funkce orchestrátoru jako vstup nebo jako návratovou hodnotu funkce 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.
Rozhraní API pro blokování vláken
Blokování rozhraní API, jako je "spánek", může způsobit problémy s výkonem a škálováním funkcí orchestrátoru a měli byste se jim vyhnout. V plánu Azure Functions Consumption můžou dokonce vést k zbytečným poplatkům za dobu provádění. Používejte alternativy k blokování rozhraní API, pokud jsou dostupná. Pomocí časovačů Durable můžete například vytvořit zpoždění, která jsou bezpečná pro přehrávání a nezapočítávají se do doby provádění funkce orchestrátoru.
Asynchronní rozhraní API
Kód orchestrátoru nesmí nikdy spustit žádnou asynchronní operaci s výjimkou těch, které jsou definovány 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í DURABLE SDK API, jako jsou funkce plánování aktivit. Všechny ostatní typy asynchronních volání by se měly provádět uvnitř funkcí aktivity.
Asynchronní funkce JavaScriptu
Funkce orchestrátoru Jazyka JavaScript vždy deklarujte jako synchronní funkce generátoru. JavaScriptové funkce orchestrátoru nesmíte deklarovat jako async
, protože modul runtime Node.js nezaručuje, že asynchronní funkce jsou deterministické.
Koruiny Pythonu
Funkce orchestrátoru Pythonu nesmíte deklarovat jako koruiny. Jinými slovy, nikdy deklarujte funkce orchestrátoru Pythonu pomocí klíčového async
slova , protože korutinová sémantika není v souladu s modelem Durable Functions přehrávání. Funkce orchestrátoru Pythonu musíte vždy deklarovat jako generátory, což znamená, že byste měli očekávat context
, že rozhraní API použije yield
místo await
.
Rozhraní .NET Threading API
Durable Task Framework spouští kód orchestrátoru v jednom vlákně a nemůže interagovat s jinými vlákny. Spuštění asynchronního pokračování ve vlákně fondu pracovních procesů může mít za následek nedeterministické spuštění nebo zablokování. Z tohoto důvodu by funkce orchestrátoru téměř nikdy neměly používat rozhraní API pro dělení na vlákna. Například nikdy nepoužívejte ConfigureAwait(continueOnCapturedContext: false)
ve funkci orchestrátoru. Tím se zajistí, že pokračování úlohy se spustí na původní SynchronizationContext
funkci orchestrátoru .
Poznámka
Durable Task Framework se pokouší zjistit náhodné použití ne orchestrátorových vláken ve funkcích orchestrátoru. Pokud zjistí porušení, rozhraní vyvolá výjimku NonDeterministicOrchestrationException . Toto chování detekce ale nezachytí všechna porušení a neměli byste na něj záviset.
Správa verzí
Trvalá orchestrace může běžet nepřetržitě po dobu dnů, měsíců, let nebo dokonce věčně. Jakékoli aktualizace kódu provedené u Durable Functions aplikací, které ovlivňují nedokončené orchestrace, můžou narušit chování orchestrací při přehrání. Proto je důležité při provádění aktualizací kódu pečlivě plánovat. Podrobnější popis verzí kódu najdete v článku o správě verzí.
Úlohy Durable
Poznámka
Tato část popisuje podrobnosti interní implementace Durable Task Framework. Odolné funkce můžete použít i bez znalosti těchto informací. Je určena pouze k tomu, aby vám pomohla pochopit chování při přehrávání.
Úlohy, které můžou bezpečně čekat ve funkcích orchestrátoru, se někdy označují jako trvalé úlohy. Durable Task Framework vytváří a spravuje tyto úlohy. Příklady jsou úlohy, které CallActivityAsync
vrací , WaitForExternalEvent
a CreateTimer
ve funkcích orchestrátoru .NET.
Tyto odolné úlohy jsou interně spravovány TaskCompletionSource
seznamem objektů v .NET. Během přehrávání se tyto úlohy vytvářejí jako součást provádění kódu orchestrátoru. Dokončí se, protože dispečer vytvoří výčet odpovídajících událostí historie.
Úlohy se provádějí synchronně pomocí jednoho vlákna, dokud se nepřehraje celá historie. Trvalé úkoly, které nejsou dokončeny do konce přehrání historie, mají provedené příslušné akce. Například zpráva může být zaváděna do fronty pro volání funkce aktivity.
Popis chování modulu runtime v této části by vám měl pomoct pochopit, proč funkce orchestrátoru nemůže použít await
nebo yield
v neúdržitelné úloze. Existují dva důvody: vlákno dispečera nemůže čekat na dokončení úlohy a jakékoli zpětné volání této úlohy může potenciálně poškodit stav sledování funkce orchestrátoru. Některé kontroly modulu runtime jsou zavedeny, aby pomohly tato porušení rozpoznat.
Další informace o tom, jak rozhraní Durable Task Framework spouští funkce orchestrátoru, najdete ve zdrojovém kódu Durable Task na GitHubu. Konkrétně se podívejte na soubory TaskOrchestrationExecutor.cs a TaskOrchestrationContext.cs.