Tartós vezénylések

A tartós vezénylés egy vezénylő függvénnyel koordinálja más függvények végrehajtását egy megbízható, hosszú ideig futó munkafolyamatban, amely teljes egészében kódban van meghatározva. Az Orchestrator függvények a következő jellemzőkkel rendelkeznek:

  • Eljárási kóddal definiálják a munkafolyamatokat. Nincs szükség deklaratív sémákra vagy tervezőkre.
  • Más függvényeket szinkron módon és aszinkron módon hívnak meg. Az úgynevezett függvények kimenete menthető helyi változókba.
  • Automatikusan ellenőrzési pontot készítenek a végrehajtás előrehaladásáról, amikor a függvény meghív egy await vagy yield operátort, így a helyi állapot nem vész el, amikor a folyamat vagy a virtuális gép újraindul.
  • Támogatják a hosszú ideig futó folyamatokat. A orchestration példány teljes élettartama lehet másodperc, nap vagy hónap, vagy beállíthatja, hogy a példány soha se érjen véget.

Ez a cikk áttekintést nyújt a tartós vezénylésekről, beleértve a vezénylési identitást, az esemény-beszerzést, a végrehajtási előzményeket és az olyan gyakori munkafolyamat-mintákat, mint az alvezénylések, a tartós időzítők és a hibakezelés.

Az Durable Functions-alkalmazásokban elérhető függvénytípusokkal kapcsolatos információkért lásd: Durable Task programozási modell.

Jótanács

Ha a C#-ot a .NET izolált feldolgozómodellel használja, akkor a vezényléseket függvényalapú megközelítéssel (attribútumokkal rendelkező statikus metódusokkal) vagy [Function] megközelítéssel (azoktól TaskOrchestrator<TInput, TOutput>öröklő osztályok) is megírhatja. Az osztályalapú megközelítéshez a Microsoft.DurableTask.Generators forrásgenerátorcsomag szükséges, és erősen gépelt meghívásokat biztosít. További információ: Forrásgenerátorok és osztályalapú szintaxis. A cikkben szereplő C#-kód példák mindkét megközelítést mutatják be.

A Durable Task SDK-k ugyanazokat a vezénylési képességeket biztosítják, mint a Durable Functions, amellyel megbízható, hosszan futó munkafolyamatokat hozhat létre párhuzamos feldolgozással és eseményvezérelt koordinációval. A Durable Functionstől eltérően a Durable Task SDK vezénylések különálló alkalmazásokként futnak, amelyeket a Durable Task Scheduler támogatott.

Orchesztációs identitás

Egy orchestráció minden példánya rendelkezik egy példányazonosítóval, más néven példányazonosítóval. Alapértelmezés szerint minden példányazonosító egy automatikusan generált globálisan egyedi azonosító (GUID). A példányazonosítók azonban bármilyen felhasználó által létrehozott sztringértékek is lehetnek. Minden orchesztrációs példányazonosítónak egyedinek kell lennie egy feladatközponton belül.

A példányazonosítókra a következő szabályok vonatkoznak:

  • A karaktereknek 1 és 100 karakter közöttinek kell lenniük.
  • Nem kezdődhetnek @-vel.
  • Nem tartalmazhatnak /, \vagy #? karaktereket.
  • Nem tartalmazhatnak vezérlőkaraktereket.

Megjegyzés:

Ha lehetséges, használjon automatikus példányazonosítókat. A felhasználó által létrehozott példányazonosítók olyan helyzetekre szolgálnak, amikor a vezénylési példány és egy külső alkalmazásspecifikus entitás, például egy vásárlási megrendelés vagy egy dokumentum között egy-az-egyhez megfeleltetés van.

Megjegyzés:

A karakterkorlátozási szabályok tényleges érvényesítése az alkalmazás által használt társzolgáltatótól függően változhat. A helyes viselkedés és kompatibilitás biztosítása érdekében kövesse az előző példányazonosító-szabályokat.

A vezénylés példányazonosítója a legtöbb példánykezelési művelethez szükséges paraméter. A példányazonosítók a diagnosztika szempontjából is fontosak. Ezeket például akkor használja, amikor hibaelhárítási vagy elemzési célokra az Application Insights vezényléskövetési adatai között keres . Ezért mentse a létrehozott példányazonosítókat egy külső helyre, amely megkönnyíti a későbbi hivatkozásokat, például egy adatbázis- vagy alkalmazásnaplót.

A vezénylés példányazonosítója a legtöbb példánykezelési művelethez szükséges paraméter. A példányazonosítók a diagnosztika szempontjából is fontosak, ezért mentse a létrehozott példányazonosítókat egy külső helyre, amely megkönnyíti a későbbi hivatkozásokat, például egy adatbázist vagy alkalmazásnaplót.

Reliability

Az Orchestrator-függvények az eseményforrás mintát használják a végrehajtási állapot megbízható fenntartásához. A vezénylés aktuális állapotának közvetlen tárolása helyett a Durable Task Framework egy csak hozzáfűző tárolót használ a függvényvezénylés által végrehajtott műveletek teljes sorozatának rögzítéséhez. A csak hozzáfűző tárolók számos előnnyel járnak a teljes futtatókörnyezet állapotának kiírásához képest. Az előnyök közé tartozik a nagyobb teljesítmény, a méretezhetőség és a válaszkészség. Emellett végleges konzisztenciát is kaphat a tranzakciós adatokhoz, a teljes auditnaplókhoz és az előzményekhez. Az auditnaplók megbízható kompenzáló műveleteket támogatnak.

A Durable Task Framework transzparens módon használja az esemény-beszerzést. A színfalak mögött a vezénylő függvény egy await operátort használ a C#-ban, és egy yield operátort JavaScriptben és Python. Ezek az operátorok visszavetik a vezénylő szál vezérlését a Durable Task Framework diszpécsernek. Java-ban a .await() hívása egy feladaton átadja az ellenőrzést a diszpécsernek a Throwable egyéni példányán keresztül. A diszpécser ezután véglegesíti azokat az új műveleteket, amelyeket a vezénylő függvény a tárolóba ütemez. Ilyen műveletek például egy vagy több gyermekfüggvény meghívása vagy egy tartós időzítő ütemezése. Az átlátható véglegesítési művelet frissíti a vezénylési példány végrehajtási előzményeit, azáltal hogy az összes új eseményt hozzáfűzi a tárhelyhez, hasonlóan egy csak hozzáfűzést támogató naplóhoz. Hasonlóképpen, a véglegesítési művelet üzeneteket hoz létre a tárolóban a tényleges munka ütemezéséhez. Ezen a ponton az orchestrator függvény eltávolítható a memóriából.

A Durable Functions alapértelmezés szerint az Azure Storage-t használja futtatókörnyezeti állapottárolóként, de más tárolószolgáltatók is támogatottak.

Ha egy vezénylési függvény több feladatot kap (például válaszüzenet érkezik, vagy egy tartós időzítő lejár), a vezénylő felébreszti és újra végrehajtja a teljes függvényt az elejétől kezdve a helyi állapot újraépítéséhez. A visszajátszás során, ha a kód megpróbál meghívni egy függvényt (vagy bármilyen más aszinkron munkát végez), a Durable Task Framework az aktuális vezénylés végrehajtási előzményeit tekinti át. Ha úgy találja, hogy a tevékenység már végrehajtotta és eredményt adott, visszajátssza a függvény eredményét, és a vezénylő kód továbbra is fut. A visszajátszás addig folytatódik, amíg a függvénykód be nem fejeződik, vagy amíg új aszinkron munkát nem ütemez.

Megjegyzés:

Ahhoz, hogy a visszajátszási minta megfelelően és megbízhatóan működjön, a vezénylő függvény kódjának determinisztikusnak kell lennie. A nemdeterminisztikus vezénylőkód futásidejű hibákat vagy más váratlan viselkedést eredményezhet. A vezénylő függvények kódkorlátozásairól további információt az Orchestrator függvény kódkorlátozásai című témakörben talál.

Megjegyzés:

Ha egy vezénylő függvény naplóüzeneteket bocsát ki, a visszajátszási viselkedés duplikált naplóüzenetek küldéséhez vezethet. Ha szeretné megtudni, hogy miért fordul elő ez a viselkedés, és hogyan lehet megkerülni, tekintse meg a visszajátszásmentes naplózást.

Orkesztrációs előzmények

A Durable Task Framework eseményalapú viselkedése szorosan összefügg az ön által írt orchestrátorfüggvény-kóddal. Tegyük fel, hogy rendelkezik egy tevékenységláncoló orchestrátor függvénnyel, például az alábbi példával.

Izolált munkavállalói modell
[Function("HelloCities")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var outputs = new List<string>();

    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

    // Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
    return outputs;
}

Osztályalapú modell (izolált munkafolyamat)

Az osztályalapú megközelítés egy forrásgenerátort használ, és a Microsoft.DurableTask.Generators NuGet csomagot igényli.

using Microsoft.DurableTask;

[DurableTask]
public class HelloCities : TaskOrchestrator<object?, List<string>>
{
    public override async Task<List<string>> RunAsync(
        TaskOrchestrationContext context, object? input)
    {
        var outputs = new List<string>();

        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

        // Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
        return outputs;
    }
}

Folyamaton belüli modell
[FunctionName("HelloCities")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var outputs = new List<string>();

    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

    // Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
    return outputs;
}
using Microsoft.DurableTask;

[DurableTask]
public class HelloCities : TaskOrchestrator<object?, List<string>>
{
    public override async Task<List<string>> RunAsync(TaskOrchestrationContext context, object? input)
    {
        var outputs = new List<string>();

        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
        outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

        return outputs;
    }
}

Amikor egy tevékenységfüggvény ütemezve van, a Durable Task Framework különböző ellenőrzőpontokon menti a függvény végrehajtási állapotát. Minden ellenőrzési ponton a keretrendszer egy tartós háttértárba menti az állapotot. Ezt az állapotot vezénylési előzményeknek nevezzük.

Előzménytábla

A Durable Task Framework általában a következőket végzi el minden ellenőrzőponton:

  • A végrehajtási előzményeket tartós tárolóba menti.
  • Sorba állítja az üzeneteket azokhoz a funkciókhoz, amelyeket az orchesztáló meghívni szeretne.
  • Maga a vezénylő számára is lekérdezi az üzeneteket, például a tartós időzítőüzeneteket.

Ha az ellenőrzőpont elkészült, az orkesztráló függvény eltávolítható a memóriából, amíg nincs több munka számára.

Megjegyzés:

Az Azure Storage nem biztosít tranzakciós garanciát a táblatárolók és az üzenetsorok közötti adatkonzisztenciára az adatok mentésekor. A hibák kezeléséhez a Durable Functions Azure Storage-szolgáltatóvégleges konzisztenciamintákat használ. Ezek a minták segítenek biztosítani, hogy ne vesszenek el adatok, ha egy ellenőrzőpont közepén összeomlik vagy megszakad a kapcsolat. Az alternatív tárolószolgáltatók, például a Durable Functions Microsoft SQL Server (MSSQL) tárolószolgáltató erősebb konzisztenciagaranciát biztosíthatnak.

Amikor a korábban bemutatott függvény befejeződik, az előzményei a Table Storage alábbi táblázatában szereplő adatokhoz hasonlóan néznek ki. A bejegyzések lerövidítettek az illusztráció céljából.

PartitionKey (InstanceId) Eseménytípus Időbélyeg Bemenet Név Result Status
eaee885b VégrehajtásElindult 2021-05-05T18:45:28.852Z null HelloCities
eaee885b OrchestrátorElindult 2021-05-05T18:45:32.362Z
eaee885b Ütemezett feladat 2021-05-05T18:45:32.670Z MonddHelló
eaee885b OrkészreállításBefejeződött 2021-05-05T18:45:32.670Z
eaee885b Feladat befejezve 2021-05-05T18:45:34.201Z """Hello Tokió!"""
eaee885b OrchestrátorElindult 2021-05-05T18:45:34.232Z
eaee885b Ütemezett feladat 2021-05-05T18:45:34.435Z MonddHelló
eaee885b OrkészreállításBefejeződött 2021-05-05T18:45:34.435Z
eaee885b Feladat befejezve 2021-05-05T18:45:34.763Z """Hello Seattle!"""
eaee885b OrchestrátorElindult 2021-05-05T18:45:34.857Z
eaee885b Ütemezett feladat 2021-05-05T18:45:34.857Z MonddHelló
eaee885b OrkészreállításBefejeződött 2021-05-05T18:45:34.857Z
eaee885b Feladat befejezve 2021-05-05T18:45:34.919Z """Hello London!"""
eaee885b OrchestrátorElindult 2021-05-05T18:45:35.032Z
eaee885b OrkészreállításBefejeződött 2021-05-05T18:45:35.044Z
eaee885b Végrehajtás befejezve 2021-05-05T18:45:35.044Z "[""Hello Tokyo!"",""Hello Seattle!"","Hello London!""]" Befejeződött

A táblaoszlopok a következő értékeket tartalmazzák:

  • PartitionKey: A vezénylés példányazonosítója.
  • EventType: Az esemény típusa. Az összes előzményesemény-típus részletes leírása: Durable Task Framework History Events.
  • Időbélyeg: Az előzményesemény koordinált univerzális időbélyege.
  • Bemenet: A függvény JSON-formátumú bemenete.
  • Név: A meghívott függvény neve.
  • Eredmény: A függvény kimenete, pontosabban annak visszatérési értéke.

Figyelmeztetés

Ez a táblázat hibakeresési eszközként hasznos, de formátuma és tartalma megváltozhat a Durable Functions bővítmény fejlődésével.

Minden alkalommal, amikor a függvény a feladat befejezésére való várakozás után folytatódik, a Durable Task Framework az alapoktól újrafuttatja a vezénylő függvényt. Minden újrafuttatáskor a végrehajtási előzményeket tekinti át annak megállapításához, hogy az aktuális aszinkron tevékenység befejeződött-e. Ha a végrehajtási előzmények azt mutatják, hogy a tevékenység már befejeződött, a keretrendszer visszajátssza a tevékenység kimenetét, és továbblép a következő tevékenységre. Ez a folyamat addig folytatódik, amíg a teljes végrehajtási előzmény vissza nem játszódik. Az aktuális végrehajtási előzmények visszajátszása után a rendszer visszaállítja a helyi változókat a korábbi értékekre.

Jellemzők és minták

A következő szakaszok a vezénylési függvények funkcióit és mintáit ismertetik.

Részvezénylések a vezénylő függvényekben

Az orchestrator függvények meghívhatnak activity függvényeket, de más orchestrator függvényeket is. Például, egy nagyobb vezénylést hozhat létre a vezénylő függvények könyvtárából. Egy vezénylőfüggvény több példányát is futtathatja párhuzamosan.

További információkért és példákért lásd: Al-vezénylések a Durable Functions-ben (Azure Functions).

Tartós időzítők

A vezénylések tartós időzítőket ütemezhetnek késések implementálásához vagy időtúllépési kezelés beállításához aszinkron műveletekhez. Használjon tartós időzítőket a vezénylési függvényekben a nyelvi natív sleep API-k helyett.

További információkért és példákért lásd: Timers in Durable Functions (Azure Functions).

Külső események

Az Orchestrator-függvények megvárhatják, amíg a külső események frissítik a vezénylési példányt. Ez a Durable Functions funkció gyakran hasznos emberi interakciók vagy más külső visszahívások kezeléséhez.

További információkért és példákért lásd: Külső események kezelése a Durable Functionsben (Azure Functions)

Hibakezelés

Az Orchestrator függvények használhatják a programozási nyelv hibakezelési funkcióit. Az orkesztációs kód támogatja a meglévő try/catch mintákat.

Az Orchestrator-függvények újrapróbálkozési szabályzatokat is hozzáadhatnak az általuk hívott tevékenységhez vagy al-vezénylő függvényekhez. Ha egy tevékenység vagy alvezénylő függvény kivétellel meghiúsul, a megadott újrapróbálkozási szabályzat automatikusan késleltetheti és újrapróbálkozza a végrehajtást egy megadott számú alkalommal.

Megjegyzés:

Ha egy orchestrációs függvény elosztatlan kivétellel rendelkezik, az orchestrációs példány Failed állapotban fejeződik be. Egy vezénylési példány nem próbálható újra, miután meghiúsul.

További információkért és példákért lásd: Hibakezelés a Durable Functions (Azure Functions) dokumentációban.

Kritikus szakaszok (Durable Functions 2.x, jelenleg csak .NET)

Az orchestration példányok egyszálúak, így a versenyfeltételek nem jelentenek problémát az orchestrationen belül. A versenyfeltételek azonban akkor lehetségesek, ha a vezénylések külső rendszerekkel kommunikálnak. A külső rendszerekkel való interakció során a versenyhelyzetek mérséklése érdekében a vezénylő függvények a .NET-ben egy metódussal definiálhatják a LockAsync.

Az alábbi mintakód egy kritikus szakaszt definiáló vezénylő függvényt mutat be. A LockAsync metódust használja, hogy belépjen a kritikus szakaszba. Ehhez a módszerhez egy vagy több hivatkozást kell átadni egy tartós entitásnak, amely tartósan kezeli a zárolási állapotot. A vezénylésnek csak egyetlen példánya tudja egyszerre végrehajtani a kódot a kritikus szakaszban.

[FunctionName("Synchronize")]
public static async Task Synchronize(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var lockId = new EntityId("LockEntity", "MyLockIdentifier");
    using (await context.LockAsync(lockId))
    {
        // Critical section. Only one orchestration can enter at a time.
    }
}

A LockAsync módszer lekéri a tartós zárakat, és visszaad egy IDisposable objektumot, amely a kritikus szakaszt befejezi, amikor eldobásra kerül. Ez az IDisposable eredmény blokkokkal using együtt használható a kritikus szakasz szintaktikai ábrázolásának lekéréséhez. Amikor egy vezénylő függvény kritikus szakaszba lép, csak egy példány tudja végrehajtani ezt a kódblokkot. A kritikus szakaszba belépni próbáló egyéb példányok mindaddig le lesznek tiltva, amíg az előző példány ki nem lép a kritikus szakaszból.

A kritikus szakasz funkció a tartós entitások módosításainak összehangolásához is hasznos. A kritikus szakaszokról további információt az Entitások koordinációja című témakörben talál.

Megjegyzés:

Kritikus szakaszok érhetők el a Durable Functions 2.0-ban. Jelenleg csak .NET folyamaton belüli vezénylések implementálják ezt a funkciót. Az entitások és a kritikus szakaszok még nem érhetők el a Durable Functionsben a .NET izolált feldolgozói vezénylésekhez.

HTTP-végpontokra irányuló hívások (Durable Functions 2.x)

Az Orchestrator-függvények nem végezhetnek I/O-műveleteket az Orchestrator függvénykód-megkötéseiben leírtak szerint. Ennek a korlátozásnak a tipikus megkerülő megoldása az, hogy beburkolja azokat a kódokat, amelyeknek I/O-műveleteket kell végrehajtaniuk egy tevékenységfüggvényben. Azok az orchestruációk, amelyek külső rendszerekkel lépnek interakcióba, gyakran használnak tevékenységfüggvényeket HTTP-hívások végzésére és az eredmények orchestruációhoz való visszajuttatására.

A gyakori minta egyszerűsítése érdekében a vezénylő függvények a metódus használatával közvetlenül meghívhatják a CallHttpAsync HTTP API-kat.

Izolált munkavállalói modell
[Function("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

    // Make an HTTP GET request to the specified endpoint.
    DurableHttpResponse response = await context.CallHttpAsync(
        method: HttpMethod.Get,
        uri: url,
        content: null,
        retryOptions: null);

    if ((int)response.StatusCode == 400)
    {
        // Handle error codes.
    }
}

Folyamaton belüli modell
[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

    // Make an HTTP GET request to the specified endpoint.
    DurableHttpResponse response = 
        await context.CallHttpAsync(HttpMethod.Get, url);

    if ((int)response.StatusCode == 400)
    {
        // Handle error codes.
    }
}

Az alapszintű kérés- és válaszminták támogatása mellett a módszer támogatja a gyakori aszinkron HTTP 202 lekérdezési minták automatikus kezelését. A külső szolgáltatásokkal való hitelesítést is támogatja felügyelt identitások használatával.

További információkért és részletes példákért tekintse meg a HTTP-funkciókat.

Megjegyzés:

A HTTP-végpontok közvetlenül a vezénylő függvényekből való meghívása a Durable Functions 2.0-s és újabb verzióiban érhető el.

Több paraméter átadása tevékenységfüggvényeknek

Nem lehet közvetlenül több paramétert átadni egy tevékenységfüggvénynek. A javaslat objektumok vagy összetett objektumok tömbjének átadására vonatkozik.

Izolált munkavállalói modell

A .NET-ben használjon szerializálható összetett típust, például rekordot több paraméter átadásához.

public record CourseInfo(string Major, int UniversityYear);

[Function("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    int universityYear = context.GetInput<int>();
    CourseInfo courseInfo = new("ComputerScience", universityYear);
    object courseRecommendations = await context.CallActivityAsync<object>(
        "CourseRecommendations", courseInfo);
    return courseRecommendations;
}

Folyamaton belüli modell

A .NET-ben szerializálható összetett típussal több paramétert adhat át. A következő minta egy egyszerű osztályt használ:

public class CourseInfo
{
    public string Major { get; set; }
    public int UniversityYear { get; set; }
}

[FunctionName("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var input = new CourseInfo
    {
        Major = "ComputerScience",
        UniversityYear = context.GetInput<int>()
    };

    object courseRecommendations = await context.CallActivityAsync<object>(
        "CourseRecommendations",
        input);
    return courseRecommendations;
}

A .NET rendszerében a rekordtípusok és a tuple-ök használatával több paramétert lehet átküldeni egyetlen összetett objektumként.

using Microsoft.DurableTask;

public record LocationInfo(string City, string State);

[DurableTask]
public class GetWeatherOrchestration : TaskOrchestrator<object?, string>
{
    public override async Task<string> RunAsync(TaskOrchestrationContext context, object? input)
    {
        var location = new LocationInfo("Seattle", "WA");
        string weather = await context.CallActivityAsync<string>("GetWeather", location);
        return weather;
    }
}

Következő lépések