Az Orchestrator függvénykódjának korlátozásai

Állapotalapú alkalmazások létrehozása a Durable Functions segítségével. Ez a Azure Functions kiterjesztése. A orchestrator függvény segítségével koordinálhatja a függvényalkalmazás többi Durable Functionját. Az állapottartó, megbízható vezénylő (orchestrátor) függvényeket úgy alakították ki, hogy hosszú ideig futtathatók legyenek.

Állapotalapú, hibatűrő munkafolyamatokat hozhat létre a Durable Task SDK-kkal .NET, Python és Java. Vezénylő használatával koordinálhatja a tevékenységeket és az alvezényléseket. A rendszervezérlők állapotalapúak, megbízhatók, és úgy készültek, hogy hosszú ideig tartósan működjenek.

Vezénylői kódkorlátozások

Az Orchestrator-függvények az eseményforrás használatát alkalmazzák a megbízható végrehajtás és a helyi változó állapot fenntartása érdekében. A vezénylőkód visszajátszási viselkedése kényszereket hoz létre a vezénylő függvényben írható kód típusára. A vezénylőfüggvényeknek például determinisztikusnak kell lenniük: a vezénylő függvények többször is lejátszhatók, és minden alkalommal ugyanazt az eredményt kell eredményezniük.

Az orchestratiók eseményforrás használatával biztosítják a megbízható végrehajtást és a helyi változó állapot fenntartását. A vezénylőkód visszajátszási viselkedése korlátozásokat hoz létre a vezénylőbe írható kód típusára. A vezénylőknek például determinisztikusnak kell lenniük: a vezénylők többször is lejátszanak, és minden alkalommal ugyanazt az eredményt kell eredményezniük.

Determinisztikus API-k használata

Az alábbiakban néhány egyszerű útmutatást talál a kód determinisztikusságának biztosításához.

Api-kat hívhat meg a célnyelvekből a vezénylő függvényekben, de csak determinisztikus API-kat használjon. A determinisztikus API mindig ugyanazt az értéket adja vissza ugyanahhoz a bemenethez, függetlenül attól, hogy mikor vagy milyen gyakran hívják.

Az alábbi szakaszok útmutatást nyújtanak az API-król és azokról a mintákról, amelyek nem determinisztikusak . Ezek a korlátozások csak a vezénylő függvényekre vonatkoznak. Más függvénytípusok nem rendelkeznek ilyen korlátozásokkal.

Az alábbiakban néhány egyszerű útmutatást talál a kód determinisztikusságának biztosításához.

API-kat hívhat meg vezénylőkben a célnyelvekből, de csak determinisztikus API-kat használjon. A determinisztikus API mindig ugyanazt az értéket adja vissza ugyanahhoz a bemenethez, függetlenül attól, hogy mikor vagy milyen gyakran hívják.

Az alábbi szakaszok útmutatást nyújtanak az API-król és azokról a mintákról, amelyek nem determinisztikusak . Ezek a korlátozások csak a vezénylőkre vonatkoznak. A tevékenységek nem rendelkeznek ilyen korlátozásokkal.

Megjegyzés:

Ez a cikk a vezénylői kód általános korlátozásait ismerteti, de nem átfogó. Összpontosítson arra, hogy egy API determinisztikus-e. Ezzel a gondolkodásmóddal általában a listára való hivatkozás nélkül is megállapíthatja, hogy mely API-k használhatók biztonságosan.

Dátumok és időpontok

Az időalapú API-k nem determinisztikusak, és soha nem használhatók vezénylési funkciókban. Minden orchestrátor függvény visszajátszás más értéket ad. Ehelyett használja a Durable Functions egyenértékű API-t az aktuális dátum vagy idő lekéréséhez, amely a visszajátszások során konzisztens marad.

Ne használjon DateTime.Now, DateTime.UtcNowvagy azzal egyenértékű API-kat az aktuális idő lekéréséhez. Az olyan osztályokat, mint Stopwatch, is el kell kerülni. A .NET folyamaton belüli vezénylési függvényekhez használja a IDurableOrchestrationContext.CurrentUtcDateTime tulajdonságot az aktuális idő lekéréséhez. Az elkülönített .NET vezénylőfüggvények esetén használja a TaskOrchestrationContext.CurrentDateTimeUtc tulajdonságot az aktuális idő lekérésére.

DateTime startTime = context.CurrentUtcDateTime;
// do some work
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);

Az időalapú API-k nem determinisztikusak, és nem használhatók vezénylőkben. Minden orchestrátor újrajátszása más értéket eredményez. Ehelyett használja a Durable Task SDK egyenértékű API-t az aktuális dátum vagy idő lekéréséhez, amely a visszajátszások között konzisztens marad.

Ne használjon DateTime.Now, DateTime.UtcNowvagy azzal egyenértékű API-kat az aktuális idő lekéréséhez. Az olyan osztályokat, mint Stopwatch, is el kell kerülni. Használja a TaskOrchestrationContext.CurrentUtcDateTime tulajdonságot az aktuális idő lekéréséhez.

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

GUID-k és UUID-k

A véletlenszerű GUID-t vagy UUID-t visszaadó API-k nemdeterminisztikusak, mert a létrehozott érték minden visszajátszásnál eltérő. A nyelvtől függően elérhető lehet egy beépített API a determinisztikus GUID-k vagy UUID-k létrehozásához. Ellenkező esetben egy tevékenységfüggvényt használva véletlenszerűen generált GUID-t vagy UUID-t lehet létrehozni.

Az olyan API-k, mint Guid.NewGuid(), helyett használja a környezeti objektum NewGuid() API-ját egy véletlenszerű GUID létrehozásához, amely biztonságos a vezénylő visszajátszásához.

Guid randomGuid = context.NewGuid();

Megjegyzés:

A GUID-ok, amelyeket az orchestration környezet API-kkal hoztak létre, 5-ös típusú UUID-k.

A véletlenszerű GUID-t vagy UUID-t visszaadó API-k nemdeterminisztikusak, mert a létrehozott érték minden visszajátszásnál eltérő. A nyelvtől függően elérhető lehet egy beépített API a determinisztikus GUID-k vagy UUID-k létrehozásához. Ellenkező esetben egy tevékenység használatával véletlenszerűen generált GUID-t vagy UUID-t ad vissza.

Az olyan API-k, mint Guid.NewGuid(), helyett használja a környezeti objektum NewGuid() API-ját egy véletlenszerű GUID létrehozásához, amely biztonságos a vezénylő visszajátszásához.

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

Megjegyzés:

A GUID-ok, amelyeket az orchestration környezet API-kkal hoztak létre, 5-ös típusú UUID-k.

Véletlenszerű számok

Tevékenységfüggvény használatával véletlenszerű számokat ad vissza egy vezénylő függvénynek. A tevékenységfüggvények visszatérési értékei mindig biztonságosan visszajátszhatók, mert el vannak mentve az orchestrációs előzményekbe.

Alternatív megoldásként használhat véletlenszerű számgenerátort rögzített magértékkel közvetlenül egy vezénylőfüggvényben. Ez a módszer mindaddig biztonságos, amíg az egyes vezénylési visszajátszásokhoz ugyanazt a számsorozatot hozza létre.

Egy tevékenység használatával véletlenszerű számokat ad vissza egy vezénylőnek. A tevékenységek visszatérési értékei mindig biztonságosak a visszajátszáshoz, mert elmentésre kerülnek az orchestrációs előzményekbe.

Alternatív megoldásként közvetlenül egy orchestration rendszerben használhat véletlenszám-generátort rögzített magértékkel. Ez a módszer mindaddig biztonságos, amíg az egyes vezénylési visszajátszásokhoz ugyanazt a számsorozatot hozza létre.

Kötések

Ne használjon kötéseket orkestrációs függvényekben, beleértve az orkestrációs ügyfél - és a entitásügyfél-kötéseket is. Bemeneti és kimeneti kötéseket csak ügyfél- vagy tevékenységfüggvényekben használhat. Az Orchestrator függvények többször is lejátszhatók, ami nemdeterminista és duplikált I/O-t okoz külső rendszerekkel.

Az vezénylők nem végezhetnek közvetlen I/O-műveleteket külső rendszerekkel. Az input/output műveletek áthelyezése tevékenységekre. A vezénylők többször is újrajátszhatók, ami nem determinisztikus és duplikált I/O-t okozhat külső rendszerekkel.

Statikus változók

A statikus változók idővel változhatnak, így nem biztonságosak a vezénylő függvények számára. Kerülje a statikus változók használatát a vezénylő függvényekben, mert az értékek idővel változhatnak, ami nem meghatározott futásidejű viselkedést eredményez. Ehelyett használjon állandókat, vagy korlátozza a statikus változók használatát a tevékenységfüggvényekre.

A statikus változók idővel változhatnak, így nem biztonságosak a vezénylők számára. Kerülje a statikus változók használatát a vezénylőkben, mert az értékek idővel változhatnak, ami nemdeterminista futtatókörnyezeti viselkedést eredményez. Ehelyett használjon állandókat, vagy korlátozza a statikus változók használatát tevékenységekre.

Megjegyzés:

A Azure Functions statikus változóinak használata a vezénylő függvényeken kívül is problémás lehet, mivel nincs garancia arra, hogy a statikus állapot több függvény végrehajtása során is megmarad. Kerülje a statikus változókat, kivéve bizonyos használati eseteket, például a memóriabeli gyorsítótárazást a tevékenységben vagy entitásfüggvényekben.

Környezeti változók

A vezénylő függvények környezeti változói idővel változhatnak, ami nemdeterminista futtatókörnyezeti viselkedést eredményez. Ha egy vezénylőfüggvénynek környezeti változóban meghatározott konfigurációra van szüksége, a konfigurációs értéket bemenetként vagy tevékenységfüggvény visszatérési értékeként kell átadnia a vezénylő függvénynek.

A vezénylők környezeti változói idővel változhatnak, ami nemdeterminista futtatókörnyezeti viselkedést eredményez. Ha egy vezénylőnek környezeti változóban meghatározott konfigurációra van szüksége, a konfigurációs értéket bemenetként vagy egy tevékenység visszatérési értékeként kell átadnia a vezénylőnek.

Hálózat és HTTP

Használj tevékenységfüggvényeket kimenő hálózati hívások indításához. Ha HTTP-hívást kell kezdeményeznie a vezénylő függvényből, használhatja a tartós HTTP API-kat is.

Tevékenységek használata kimenő hálózati hívások indításához. Az vezénylőknek soha nem szabad közvetlen HTTP-hívásokat vagy más hálózati kéréseket kezdeményeznie, mert ezek a műveletek nem meghatározottak.

Szálblokkoló API-k

A sleep api-k blokkolása teljesítménybeli és méretezési problémákat okozhat a vezénylő függvények esetében, és szükségtelen végrehajtási időköltségeket eredményezhet a Azure Functions Használati tervben. Használjon alternatív megoldásokat, ha elérhetők. Tartós időzítőkkel például olyan késéseket hozhat létre, amelyek biztonságosak az újrajátszáshoz, és nem számítanak bele a vezénylés végrehajtási idejébe.

Az olyan API-k blokkolása, mint az "alvás" teljesítménybeli és méretezési problémákat okozhat a vezénylők számára, ezért kerülni kell. Megbízható időzítőket használjon olyan késleltetések létrehozásához, amelyek biztonságosan használhatók az újrajátszáshoz.

Használja context.CreateTimer() helyett Task.Delay() vagy Thread.Sleep().

// Don't use Task.Delay() or Thread.Sleep()
// Use context.CreateTimer() instead
await context.CreateTimer(context.CurrentUtcDateTime.AddMinutes(5), CancellationToken.None);

Async API-k

Az orchestrator-kódnak soha nem szabad aszinkron műveletet elindítania, kivéve a vezénylési eseményindító környezeti objektuma által meghatározott műveleteket. Soha ne használjon például Task.Run, Task.Delay és HttpClient.SendAsync .NET vagy setTimeout és setInterval JavaScriptben. A vezénylő függvények csak tartós SDK API-k használatával ütemezhetnek aszinkron munkát, például ütemezési tevékenységfüggvényeket. Minden más típusú aszinkron meghívást a tevékenységfüggvényeken belül kell végrehajtani.

Az orchestrator-kódnak soha nem szabad aszinkron műveletet elindítania, kivéve a vezénylési környezet objektuma által meghatározott műveleteket. Például soha ne használja a Task.Run, Task.Delay és HttpClient.SendAsync elemeket a .NET-ben. A vezénylőknek csak aszinkron munkát kell ütemezni a Durable Task SDK API-kkal, például az ütemezési tevékenységekkel. Minden más típusú aszinkron meghívást a tevékenységeken belül kell végrehajtani.

Aszinkron JavaScript-függvények

Deklarálja a JavaScript-vezénylő függvényeket szinkron generátorfüggvényekként. Ne deklarálja a JavaScript-vezénylő függvényeket, async mert a Node.js futtatókörnyezet nem garantálja a függvények determinisztikus viselkedését async .

Python coroutines

Ne deklarálja a Python vezérlő függvényeket korutinokként. Ne használja a async kulcsszót, mert a korutin szemantikája nem igazodik a Durable Functions visszajátszási modellhez. Deklarálja a Python orchestrator függvényeket generátorként, és használja a yield a await helyett a context API-val.

Nem deklarálhat Python orchestrátorokat korutinokként. Más szóval soha ne deklaráljon Python vezénylőket a async kulcsszóval, mert a coroutine szemantikája nem igazodik a Durable Task visszajátszási modelljéhez. A Python vezénylőket mindig generátorként kell deklarálnia, ami azt jelenti, hogy yield kell használnia await helyett a környezeti API-k meghívásakor.

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

.NET szálkezelés API-k

A Durable Task Framework egyetlen szálon futtat vezénylési kódot, és nem tud más szálakkal kommunikálni. Az aszinkron folytatások futtatása egy feldolgozókészlet-szálon a vezénylés végrehajtásában nem meghatározott végrehajtást vagy holtpontot eredményezhet. Ezért a vezénylő függvények szinte soha nem használhatnak szálkezelő API-kat. Például soha ne használjon ConfigureAwait(continueOnCapturedContext: false) vezénylőfüggvényben annak biztosítására, hogy a feladat folytatásai a vezénylő függvény eredeti SynchronizationContext helyén fussanak.

Megjegyzés:

A Durable Task Framework megpróbálja észlelni a nem-vezénylő szálak véletlen használatát a vezénylő függvényekben. Ha jogsértést talál, a keretrendszer egy NonDeterministicOrchestrationException kivételt eredményez. Ez az észlelési viselkedés azonban nem fog minden szabálysértést észlelni, és nem szabad attól függenie.

A Durable Task Framework egyetlen szálon futtat vezénylési kódot, és nem tud más szálakkal kommunikálni. Az aszinkron folytatások futtatása egy feldolgozókészlet-szálon a vezénylés végrehajtásában nem meghatározott végrehajtást vagy holtpontot eredményezhet. Ezért a vezénylőknek szinte soha nem szabad menetes API-kat használniuk. Például soha ne használjon ConfigureAwait(continueOnCapturedContext: false) egy orchestrátorban annak érdekében, hogy a feladatok folytatásai az eredeti orchestrátoron SynchronizationContext fussanak.

Megjegyzés:

A Durable Task Framework megpróbálja észlelni a vezénylőkben a nemvezénylő szálak véletlen használatát. Ha jogsértést talál, a keretrendszer egy NonDeterministicOrchestrationException kivételt eredményez. Ez az észlelési viselkedés azonban nem fog minden szabálysértést észlelni, és nem szabad attól függenie.

Verziókezelés

A tartós vezénylés napokig, hónapokig, évekig vagy akár örök vezénylésként is futtatható. A futtatási vezényléseket befolyásoló kódmódosítások megszakíthatják a visszajátszási viselkedést, ezért gondosan tervezze meg az alkalmazást, mielőtt frissítené. További információ: Verziószámozás.

A tartós orkesztáció napokig, hónapokig, évekig vagy akár határozatlan ideig is futtatható. A futtatási vezényléseket befolyásoló kódmódosítások megszakíthatják a visszajátszási viselkedést, ezért gondosan tervezze meg az alkalmazást, mielőtt frissítené. A gyakori verziószámozási stratégiák közé tartozik az egymás melletti üzembe helyezés és a verzióspecifikus feladatközpontok neveinek használata.

Tartós feladatok

Megjegyzés:

Ez a szakasz a Durable Task Framework belső implementációjának részleteit ismerteti. A Durable Functions használatához nem kell tudnia ezeket az információkat, de segít elmagyarázni a visszajátszási viselkedést.

A vezénylő függvényekben biztonságosan várakozó feladatokat tartós feladatoknak is nevezik. A Durable Task Framework létrehozza és kezeli ezeket a feladatokat. Ilyenek például a CallActivityAsync, WaitForExternalEvent és CreateTimer által visszaadott feladatok .NET vezénylési függvényekben.

A .NET TaskCompletionSource objektumainak listája belsőleg kezeli ezeket a tartós feladatokat. A visszajátszás során a vezénylőkód létrehozza ezeket a feladatokat. A diszpécser végrehajtja őket, miközben felsorolja a kapcsolódó előzményeseményeket.

A futtatókörnyezet szinkron módon hajtja végre a feladatokat egyetlen szálon, amíg vissza nem játssza az előzményeket. Ha egy tartós feladat nem fejeződik be az előzmények visszajátszásának végéig, a futtatókörnyezet végrehajtja a megfelelő műveleteket. A futtatókörnyezet például meghívhat egy tevékenységfüggvényt meghívó üzenetet.

Ez a futtatási viselkedés megmagyarázza, hogy a vezénylő függvény miért nem használhatja a await vagy yield egy nem-tartós feladatban. A diszpécserszál nem tudja megvárni a feladat befejezését, és a feladat visszahívásai ronthatják a vezénylő függvény nyomkövetési állapotát. A futtatókörnyezet olyan ellenőrzéseket tartalmaz, amelyek segítenek észlelni ezeket a szabálysértéseket.

A Durable Task Framework vezénylői funkcióinak végrehajtásáról a Durable Task source code on GitHub című témakörben talál további információt. Lásd: TaskOrchestrationExecutor.cs és TaskOrchestrationContext.cs.

A vezénylőkben biztonságosan várakozó feladatokat tartós feladatoknak is nevezik. A Durable Task Framework létrehozza és kezeli ezeket a feladatokat. Ilyenek például a CallActivityAsync, WaitForExternalEvent és CreateTimer által visszaadott feladatok .NET vezénylőkben.

A .NET TaskCompletionSource objektumainak listája belsőleg kezeli ezeket a tartós feladatokat. A visszajátszás során a vezénylőkód létrehozza ezeket a feladatokat. A diszpécser végrehajtja őket, miközben felsorolja a kapcsolódó előzményeseményeket.

A futtatókörnyezet szinkron módon hajtja végre a feladatokat egyetlen szálon, amíg vissza nem játssza az előzményeket. Ha egy tartós feladat nem fejeződik be az előzmények visszajátszásának végéig, a futtatókörnyezet végrehajtja a megfelelő műveleteket. A futtatókörnyezet például üzenetet jeleníthet meg egy tevékenység meghívásához.

Ez a futásidejű viselkedés megmagyarázza, hogy a vezénylő miért nem tudja használni a await vagy yield címkéket nem tartós feladatoknál. A ütemező szál nem tudja megvárni a feladat befejezését, és a feladatból érkező visszahívások ronthatják az orchestrátor nyomkövetési állapotát. A futtatókörnyezet olyan ellenőrzéseket tartalmaz, amelyek segítenek észlelni ezeket a szabálysértéseket.

Ha többet szeretne megtudni arról, hogy a Durable Task Framework hogyan hajtja végre a vezénylőket, tekintse meg a Durable Task forráskódját a GitHubon. Lásd: TaskOrchestrationExecutor.cs és TaskOrchestrationContext.cs.

Következő lépések