Verziószámozás Durable Functions (Azure Functions)
Elkerülhetetlen, hogy a függvények hozzáadva, eltávolítva és módosítva legyenek az alkalmazások élettartama során. Durable Functions lehetővé teszi a láncoló függvények összefűzését olyan módokon, amelyek korábban nem voltak lehetségesek, és ez a láncolás hatással van a verziószámozás kezelésére.
Kompatibilitástörő változások kezelése
Számos példa van a kompatibilitástörő változásokra, amelyeket figyelembe kell venni. Ez a cikk a leggyakoribbakat ismerteti. A fő téma mögöttük az áll, hogy az új és a meglévő függvényvezényléseket is érintik a függvénykód módosításai.
Tevékenység- vagy entitásfüggvény-aláírások módosítása
Az aláírás módosítása egy függvény nevének, bemenetének vagy kimenetének változására utal. Ha ez a fajta módosítás egy tevékenység- vagy entitásfüggvényen történik, az megszakíthatja az attól függő vezénylőfüggvényeket. Ez különösen igaz a típusbiztos nyelvekre. Ha a módosításnak megfelelően frissíti az orchestrator függvényt, megszakíthatja a meglévő tesztpéldányokat.
Tegyük fel például, hogy a következő vezénylőfüggvénnyel rendelkezünk.
[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
bool result = await context.CallActivityAsync<bool>("Foo");
await context.CallActivityAsync("Bar", result);
}
Ez a leegyszerűsítő függvény a Foo eredményeit veszi fel, és átadja a Barnak. Tegyük fel, hogy a Foo visszatérési értékét logikai értékről sztringre kell módosítanunk az eredményértékek szélesebb körének támogatásához. Az eredmény a következőhöz hasonló:
[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
string result = await context.CallActivityAsync<string>("Foo");
await context.CallActivityAsync("Bar", result);
}
Ez a változás jól működik a vezénylőfüggvény összes új példánya esetében, de megszakíthatja a repülés közbeni példányokat. Vegyük például azt az esetet, amikor egy vezénylési példány meghív egy nevű Foo
függvényt, visszaad egy logikai értéket, majd ellenőrzőpontokat. Ha az aláírás módosítása ezen a ponton van üzembe helyezve, az ellenőrzőponttal megadott példány azonnal meghiúsul, amikor újraindul, és visszajátssza a hívását.Foo
Ez a hiba azért fordul elő, mert az előzménytáblában szereplő eredmény logikai érték, de az új kód megpróbálja sztringértékké deszerializálni, ami váratlan viselkedést vagy futásidejű kivételt eredményez a típusbiztos nyelvek esetében.
Ez a példa csak egy a számos különböző módszer közül, amellyel egy függvény aláírásának módosítása megszakíthatja a meglévő példányokat. Általánosságban elmondható, hogy ha egy vezénylőnek módosítania kell a függvények hívási módját, akkor a változás valószínűleg problémás lesz.
A vezénylő logikája módosítása
A verziószámozási problémák másik osztálya a vezénylőfüggvény kódjának olyan módosítása, amely megváltoztatja a tesztkörnyezeti példányok végrehajtási útvonalát.
Vegye figyelembe a következő vezénylőfüggvényt:
[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
bool result = await context.CallActivityAsync<bool>("Foo");
await context.CallActivityAsync("Bar", result);
}
Most tegyük fel, hogy módosítani szeretne egy új függvényhívást a két meglévő függvényhívás között.
[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);
}
Ez a módosítás hozzáad egy új függvényhívást a SendNotification függvényhez Foo és Bar között. Nincsenek aláírásváltozások. A probléma akkor merül fel, ha egy meglévő példány újraindul a Bar hívásából. A visszajátszás során, ha a Foo eredeti hívása vissza lett adva true
, akkor a vezénylő visszajátszása meghívja a SendNotification metódust, amely nem szerepel a végrehajtási előzményeiben. A futtatókörnyezet észleli ezt az inkonzisztenciát, és nem determinisztikus vezénylési hibát okoz, mert a SendNotification hívása történt, amikor a sáv hívását várta. Ugyanez a probléma akkor fordulhat elő, ha API-hívásokat ad hozzá más tartós műveletekhez, például tartós időzítőket hoz létre, külső eseményekre vár, alvezényléseket hív meg stb.
Kockázatcsökkentési stratégiák
Íme néhány stratégia a verziószámozási kihívások kezelésére:
- Ne tegyen semmit (nem ajánlott)
- Az összes folyamatban lévő példány leállítása
- Párhuzamos üzembe helyezések
Semmit sem tehet
A verziószámozás naiv megközelítése, hogy semmit sem tesz, és hagyja, hogy a repülés közbeni vezénylési példányok meghiúsuljanak. A változás típusától függően a következő típusú hibák fordulhatnak elő.
- A vezénylések nem determinisztikus vezénylési hibával meghiúsulhatnak.
- A vezénylések határozatlan ideig elakadhatnak, és állapotot jelenthetnek
Running
. - Ha egy függvény el lesz távolítva, bármely függvény, amely megpróbálja meghívni, hibával meghiúsulhat.
- Ha a rendszer eltávolít egy függvényt az ütemezett futtatás után, akkor előfordulhat, hogy az alkalmazás alacsony szintű futásidejű hibákat tapasztal a Durable Task Framework motorban, ami súlyos teljesítménycsökkenést okozhat.
A lehetséges hibák miatt nem ajánlott a "semmit tenni" stratégia.
Az összes folyamatban lévő példány leállítása
Egy másik lehetőség az összes tesztpéldány leállítása. Ha az alapértelmezett Azure Storage-szolgáltatót használja a Durable Functions, az összes példány leállítása a belső vezérlősor és a workitem-queue üzenetsor tartalmának törlésével végezhető el. Másik lehetőségként leállíthatja a függvényalkalmazást, törölheti ezeket az üzenetsorokat, majd újraindíthatja az alkalmazást. Az üzenetsorok automatikusan újra létrejönnek, amint az alkalmazás újraindul. Előfordulhat, hogy a korábbi vezénylési példányok határozatlan ideig "Fut" állapotban maradnak, de nem fogják átnézni a naplókat hibaüzenetekkel, és nem okoznak kárt az alkalmazásban. Ez a megközelítés ideális a prototípus gyors fejlesztéséhez, beleértve a helyi fejlesztést is.
Megjegyzés
Ez a megközelítés közvetlen hozzáférést igényel a mögöttes tárolási erőforrásokhoz, és nem felelek meg az Durable Functions által támogatott összes tárolószolgáltatónak.
Párhuzamos üzembe helyezések
A kompatibilitástörő változások biztonságos üzembe helyezésének legbiztosabb módja az, ha a régebbi verziókkal együtt helyezi üzembe őket. Ez a következő technikák bármelyikével végezhető el:
- Helyezze üzembe az összes frissítést teljesen új függvényként, így a meglévő függvények is megmaradnak. Ez általában nem ajánlott az új függvényverziók hívóinak rekurzív frissítésének összetettsége miatt.
- Helyezze üzembe az összes frissítést új függvényalkalmazásként egy másik tárfiókkal.
- Helyezze üzembe a függvényalkalmazás új példányát ugyanazzal a tárfiókkal, de a feladatközpont frissített nevével. Ez új tárolási összetevők létrehozását eredményezi, amelyeket az alkalmazás új verziója használhat. Az alkalmazás régi verziója továbbra is az előző tárolóösszetevő-készlettel lesz végrehajtva.
A párhuzamos üzembe helyezés az ajánlott módszer a függvényalkalmazások új verzióinak üzembe helyezéséhez.
Megjegyzés
Ez az útmutató a párhuzamos üzembe helyezési stratégiához az Azure Storage-specifikus kifejezéseket használja, de általában az összes támogatott Durable Functions tárolószolgáltatóra vonatkozik.
Üzembe helyezési pontok
Ha párhuzamos üzembe helyezést végez Azure Functions vagy Azure App Service, javasoljuk, hogy helyezze üzembe a függvényalkalmazás új verzióját egy új üzembehelyezési ponton. Az üzembehelyezési pontok lehetővé teszik a függvényalkalmazás több példányának párhuzamos futtatását, amelyek közül csak az egyiket tekinti aktív éles tárolóhelynek . Ha készen áll arra, hogy elérhetővé tegye az új vezénylési logikát a meglévő infrastruktúrának, az egyszerűen felcserélheti az új verziót az éles üzembe helyezési pontra.
Megjegyzés
Ez a stratégia akkor működik a legjobban, ha HTTP- és webhook-eseményindítókat használ a vezénylési függvényekhez. A nem HTTP-eseményindítók, például az üzenetsorok vagy az Event Hubs esetében az eseményindító definíciójának egy olyan alkalmazásbeállításból kell származnia , amely a felcserélési művelet részeként frissül.