Správa verzí v Durable Functions (Azure Functions)

Je nevyhnutelné, aby se funkce přidávaly, odebíraly a měnily po celou dobu životnosti aplikace. Durable Functions umožňuje zřetězit funkce způsoby, které dříve nebyly možné, a toto zřetězování ovlivňuje způsob zpracování verzí.

Zpracování změn způsobujících chybu

Existuje několik příkladů změn způsobujících chybu, o které je potřeba vědět. Tento článek popisuje ty nejběžnější. Hlavním motivem za všemi z nich je to, že nové i stávající orchestrace funkcí jsou ovlivněny změnami v kódu funkce.

Změna signatur aktivit nebo funkcí entit

Změna podpisu odkazuje na změnu názvu, vstupu nebo výstupu funkce. Pokud se tento druh změny provede u funkce aktivity nebo entity, může dojít k narušení jakékoli funkce orchestrátoru, která na ní závisí. To platí zejména pro jazyky, které jsou bezpečné pro typ. Pokud aktualizujete funkci orchestrátoru tak, aby vyhovovala této změně, může dojít k narušení existujících instancí v rámci nasazení.

Předpokládejme například, že máme následující funkci orchestrátoru.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    await context.CallActivityAsync("Bar", result);
}

Tato zjednodušená funkce vezme výsledky foo a předá je baru. Předpokládejme, že potřebujeme změnit návratovou hodnotu foo z logické hodnoty na String, abychom podporovali širší škálu výsledných hodnot. Výsledek vypadá takto:

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string result = await context.CallActivityAsync<string>("Foo");
    await context.CallActivityAsync("Bar", result);
}

Tato změna funguje správně u všech nových instancí funkce orchestrátoru, ale může narušit všechny instance za každou dobu nasazení. Představte si například případ, kdy instance orchestrace volá funkci s názvem Foo, získá zpět logickou hodnotu a pak vytvoří kontrolní body. Pokud je v tomto okamžiku nasazena změna podpisu, dojde k selhání kontrolního bodu instance okamžitě při obnovení a přehrání volání Foo. K tomuto selhání dochází, protože výsledek v tabulce historie je logická hodnota, ale nový kód se ji pokusí deserializovat na hodnotu string, což vede k neočekávanému chování nebo dokonce výjimce za běhu pro typově bezpečné jazyky.

Tento příklad je jen jedním z mnoha různých způsobů, jak může změna podpisu funkce narušit existující instance. Obecně platí, že pokud orchestrátor potřebuje změnit způsob volání funkce, bude změna pravděpodobně problematická.

Změna logiky orchestrátoru

Druhou třídou problémů se správou verzí je změna kódu funkce orchestrátoru způsobem, který mění cestu provádění pro instance za běhu.

Představte si následující funkci orchestrátoru:

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    await context.CallActivityAsync("Bar", result);
}

Teď předpokládejme, že chcete provést změnu a přidat volání nové funkce mezi dvě existující volání funkce.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    if (result)
    {
        await context.CallActivityAsync("SendNotification");
    }

    await context.CallActivityAsync("Bar", result);
}

Tato změna přidá nové volání funkce SendNotification mezi Foo a Bar. Nedošlo k žádným změnám podpisu. K problému dochází při obnovení existující instance z volání na panel. Pokud původní volání Foo během přehrávání vrátilotrue, přehrání orchestrátoru zavolá metodu SendNotification, která není v historii provádění. Modul runtime zjistí tuto nekonzistence a vyvolá nedeterministický orchestrační chybu, protože zjistil volání SendNotification , když očekával, že se zobrazí volání panelu. Ke stejnému typu problému může dojít při přidávání volání rozhraní API k jiným trvalým operacím, jako je vytváření trvalých časovačů, čekání na externí události, volání dílčích orchestrací atd.

Strategie pro zmírnění rizik

Tady jsou některé strategie pro řešení problémů s správou verzí:

  • Nedělejte nic (nedoporučuje se)
  • Zastavení všech instancí za letu
  • Souběžná nasazení

Nedělejte nic

Naivní přístup ke správě verzí spočívá v tom, že neděláte nic a necháte instance průběžné orchestrace selhat. V závislosti na typu změny může dojít k následujícím typům selhání.

  • Orchestrace můžou selhat s nedetermintickou chybou orchestrace .
  • Orchestrace se můžou natrvalo zaseknout a hlásit stav Running .
  • Pokud se funkce odebere, jakákoli funkce, která se ji pokusí volat, může selhat s chybou.
  • Pokud se funkce po naplánování spuštění odebere, může v aplikaci dojít k selháním nízké úrovně modulu runtime v modulu Durable Task Framework, což může mít za následek výrazné snížení výkonu.

Vzhledem k těmto potenciálním selháním se strategie "nedělá nic" nedoporučuje.

Zastavení všech instancí za letu

Další možností je zastavit všechny spuštěné instance. Pokud pro Durable Functions používáte výchozího poskytovatele služby Azure Storage, můžete všechny instance zastavit vymazáním obsahu fronty interních ovládacích prvků a pracovních položek. Případně můžete aplikaci funkcí zastavit, odstranit tyto fronty a aplikaci znovu restartovat. Po restartování aplikace se fronty automaticky znovu vytvoří. Předchozí instance orchestrace můžou zůstat ve stavu Spuštěno po neomezenou dobu, ale nezahltí vaše protokoly zprávami o selhání ani nezpůsobí škodu vaší aplikaci. Tento přístup je ideální pro rychlý vývoj prototypů, včetně místního vývoje.

Poznámka

Tento přístup vyžaduje přímý přístup k podkladovým prostředkům úložiště a není vhodný pro všechny poskytovatele úložiště, které Durable Functions podporuje.

Souběžná nasazení

Nejopravnějším způsobem, jak zajistit bezpečné nasazení změn způsobujících chybu, je jejich nasazení souběžně s vašimi staršími verzemi. Můžete k tomu použít některou z následujících technik:

  • Nasaďte všechny aktualizace jako zcela nové funkce a stávající funkce ponechte beze změny. Obecně se to nedoporučuje kvůli složitosti, která je spojená s rekurzivní aktualizací volajících nových verzí funkcí.
  • Nasaďte všechny aktualizace jako novou aplikaci funkcí s jiným účtem úložiště.
  • Nasaďte novou kopii aplikace funkcí se stejným účtem úložiště, ale s aktualizovaným názvem centra úloh . Výsledkem je vytvoření nových artefaktů úložiště, které může používat nová verze vaší aplikace. Stará verze vaší aplikace se bude dál spouštět pomocí předchozí sady artefaktů úložiště.

Souběžné nasazení je doporučený postup nasazení nových verzí aplikací funkcí.

Poznámka

Tyto pokyny pro strategii souběžného nasazení používají termíny specifické pro Azure Storage, ale obecně platí pro všechny podporované poskytovatele Durable Functions úložiště.

Sloty nasazení

Při souběžných nasazeních v Azure Functions nebo Azure App Service doporučujeme nasadit novou verzi aplikace funkcí do nového slotu nasazení. Sloty nasazení umožňují spouštět několik kopií vaší aplikace funkcí vedle sebe, přičemž pouze jedna z nich je aktivním produkčním slotem. Až budete připraveni zveřejnit novou logiku orchestrace pro stávající infrastrukturu, může to být jednoduché, jako je prohození nové verze do produkčního slotu.

Poznámka

Tato strategie funguje nejlépe, když pro funkce orchestrátoru používáte triggery HTTP a webhooku. U triggerů jiných než HTTP, jako jsou fronty nebo event hubs, by definice triggeru měla být odvozená z nastavení aplikace , které se aktualizuje v rámci operace prohození.

Další kroky