Megosztás a következőn keresztül:


Hibák kezelése a Durable Functionsben (Azure Functions)

A Durable Functions vezénylések kódban vannak implementálva, és használhatják a programozási nyelv beépített hibakezelési funkcióit. Valójában nincs olyan új fogalom, amit meg kell tanulnia, hogy hibakezelést és kompenzációt adjon hozzá a vezénylésekhez. Van azonban néhány viselkedés, amellyel tisztában kell lennie.

Feljegyzés

Az Azure Functions Node.js programozási modelljének 4- es verziója általánosan elérhető. Az új v4-modell úgy lett kialakítva, hogy rugalmasabb és intuitívabb felhasználói élményt nyújtson JavaScript- és TypeScript-fejlesztők számára. A migrálási útmutatóban további információt olvashat a v3 és a v4 közötti különbségekről.

A következő kódrészletekben a JavaScript (PM4) a V4 programozási modellt, az új felületet jelöli.

Tevékenységfüggvények és részvezénylések hibái

A Durable Functionsben a tevékenységfüggvényeken vagy al-vezényléseken belüli kezeletlen kivételek a szabványosított kivételtípusok használatával kerülnek vissza a vezénylő függvénybe.

Vegyük például a következő orkesztáló függvényt, amely két számla közötti pénzmozgást hajt végre.

A Durable Functions C# in-process használata esetén a nem kezelt kivételek FunctionFailedException néven jelennek meg.

A kivételüzenet általában azonosítja, hogy mely tevékenységfüggvények vagy al-vezénylések okozták a hibát. A részletesebb hibainformációk eléréséhez vizsgálja meg a tulajdonságot InnerException .

[FunctionName("TransferFunds")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var transferDetails = context.GetInput<TransferOperation>();

    await context.CallActivityAsync("DebitAccount",
        new
        {
            Account = transferDetails.SourceAccount,
            Amount = transferDetails.Amount
        });

    try
    {
        await context.CallActivityAsync("CreditAccount",
            new
            {
                Account = transferDetails.DestinationAccount,
                Amount = transferDetails.Amount
            });
    }
    catch (FunctionFailedException)
    {
        // Refund the source account.
        // Another try/catch could be used here based on the needs of the application.
        await context.CallActivityAsync("CreditAccount",
            new
            {
                Account = transferDetails.SourceAccount,
                Amount = transferDetails.Amount
            });
    }
}

Feljegyzés

Az előző C#-példák a Durable Functions 2.x-hez tartoznak. A Durable Functions 1.x esetén a helyett DurableOrchestrationContexta IDurableOrchestrationContext . A verziók közötti különbségekről további információt a Durable Functions verzióiról szóló cikkben talál.

Ha az első CreditAccount függvényhívás meghiúsul, a vezénylő függvény kompenzálja az összeget a forrásfiókba történő jóváírással.

Entitásfüggvények hibái

Az entitásfüggvények kivételkezelési viselkedése a Durable Functions üzemeltetési modelltől függően eltérő:

A C#-ot használó Durable Functionsben az entitásfüggvények által létrehozott eredeti kivételtípusok közvetlenül visszakerülnek a vezénylőhöz.

[FunctionName("Function1")]
public static async Task<string> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    try
    {
        var entityId = new EntityId(nameof(Counter), "myCounter");
        await context.CallEntityAsync(entityId, "Add", 1);
    }
    catch (Exception ex)
    {
        // The exception type will be InvalidOperationException with the message "this is an entity exception".
    }
    return string.Empty;
}

[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
    switch (ctx.OperationName.ToLowerInvariant())
    {
        case "add":
            throw new InvalidOperationException("this is an entity exception");
        case "get":
            ctx.Return(ctx.GetState<int>());
            break;
    }
}

Automatikus újrapróbálkozás hiba esetén

Ha tevékenységfüggvényeket vagy részvezénylési függvényeket hív meg, megadhat egy automatikus újrapróbálkozási szabályzatot. Az alábbi példa legfeljebb háromszor próbál meghívni egy függvényt, és 5 másodpercet vár az egyes újrapróbálkozások között:

[FunctionName("TimerOrchestratorWithRetry")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var retryOptions = new RetryOptions(
        firstRetryInterval: TimeSpan.FromSeconds(5),
        maxNumberOfAttempts: 3);

    await context.CallActivityWithRetryAsync("FlakyFunction", retryOptions, null);

    // ...
}

Feljegyzés

Az előző C#-példák a Durable Functions 2.x-hez tartoznak. A Durable Functions 1.x esetén a helyett DurableOrchestrationContexta IDurableOrchestrationContext . A verziók közötti különbségekről további információt a Durable Functions verzióiról szóló cikkben talál.

Az előző példában szereplő tevékenységfüggvény-hívás egy automatikus újrapróbálkozási szabályzat konfigurálására szolgáló paramétert vesz igénybe. Az automatikus újrapróbálkozási szabályzat testreszabásának számos lehetősége van:

  • Kísérletek maximális száma: A kísérletek maximális száma. Ha az 1 értékre van állítva, nem lesz újrapróbálkozás.
  • Első újrapróbálkozási időköz: Az első újrapróbálkozási kísérlet előtti várakozási idő.
  • Visszalépési együttható: A visszakapcsolás növekedésének sebességének meghatározására használt együttható. Alapértelmezett érték: 1.
  • Maximális újrapróbálkozási időköz: Az újrapróbálkozási kísérletek közötti várakozás maximális időtartama.
  • Újrapróbálkozás időtúllépése: Az újrapróbálkozással töltött idő maximális mennyisége. Az alapértelmezett viselkedés a határozatlan ideig történő újrapróbálkozás.

Egyéni újrapróbálkozás-kezelők

A .NET vagy a Java használatakor lehetősége van újrapróbálkoztatók implementálására is a kódban. Ez akkor hasznos, ha a deklaratív újrapróbálkozási szabályzatok nem elég kifejezőek. Az egyéni újrapróbálkozási kezelőket nem támogató nyelvek esetében továbbra is lehetősége van újrapróbálkozási szabályzatok implementálására hurkok, kivételkezelés és időzítők használatával az újrapróbálkozások közötti késések injektálására.

RetryOptions retryOptions = new RetryOptions(
    firstRetryInterval: TimeSpan.FromSeconds(5),
    maxNumberOfAttempts: int.MaxValue)
    {
        Handle = exception =>
        {
            // True to handle and try again, false to not handle and throw.
            if (exception is TaskFailedException failure)
            {
                // Exceptions from TaskActivities are always this type. Inspect the
                // inner Exception to get more details.
            }

            return false;
        };
    }

await ctx.CallActivityWithRetryAsync("FlakeyActivity", retryOptions, null);

Függvény időtúllépései

Ha túl sok időt vesz igénybe, érdemes lehet megszakítani egy függvényhívást egy vezénylő függvényen belül. Ennek ma a megfelelő módja, ha egy tartós időzítőt hoz létre egy "bármely" feladatválasztóval, ahogyan az alábbi példában is látható:

[FunctionName("TimerOrchestrator")]
public static async Task<bool> Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    TimeSpan timeout = TimeSpan.FromSeconds(30);
    DateTime deadline = context.CurrentUtcDateTime.Add(timeout);

    using (var cts = new CancellationTokenSource())
    {
        Task activityTask = context.CallActivityAsync("FlakyFunction");
        Task timeoutTask = context.CreateTimer(deadline, cts.Token);

        Task winner = await Task.WhenAny(activityTask, timeoutTask);
        if (winner == activityTask)
        {
            // success case
            cts.Cancel();
            return true;
        }
        else
        {
            // timeout case
            return false;
        }
    }
}

Feljegyzés

Az előző C#-példák a Durable Functions 2.x-hez tartoznak. A Durable Functions 1.x esetén a helyett DurableOrchestrationContexta IDurableOrchestrationContext . A verziók közötti különbségekről további információt a Durable Functions verzióiról szóló cikkben talál.

Feljegyzés

Ez a mechanizmus valójában nem szünteti meg a folyamatban lévő tevékenységfüggvény végrehajtását. Ehelyett egyszerűen lehetővé teszi, hogy a vezénylő függvény figyelmen kívül hagyja az eredményt, és továbblépjen. További információkért tekintse meg az Időzítők dokumentációját.

Nem kezelt kivételek

Ha egy vezénylő függvény nem kezelt kivétellel meghiúsul, a rendszer naplózza a kivétel részleteit, és a példány állapota befejeződik Failed .

Az egyéni kivételtulajdonságok belefoglalása a FailureDetails (.NET izolált) esetén.

Ha tartós feladat munkafolyamatait futtatja a .NET izolált modellben, a rendszer automatikusan egy FailureDetails objektumba szerializálja a feladathibákat. Alapértelmezés szerint ez az objektum szabványos mezőket tartalmaz, például:

  • ErrorType – a kivételtípus neve
  • Üzenet – a kivétel üzenete
  • StackTrace – a szerializált verem nyomkövetése
  • InnerFailure – beágyazott FailureDetails objektum rekurzív belső kivételekhez

A Microsoft.Azure.Functions.Worker.Extensions.DurableTask 1.9.0-s verziótól kezdve ezt a viselkedést kiterjesztheti egy IExceptionPropertiesProvider implementálásával (a Microsoft.DurableTask.Worker 1.16.1-escsomagtól kezdve). Ez a szolgáltató határozza meg, hogy mely kivételtípusokat és azok tulajdonságait kell szerepeltetni a FailureDetails.Properties szótárban.

Feljegyzés

  • Ez a funkció csak .NET Izolált verzióban érhető el. A Java támogatása egy későbbi kiadásban lesz hozzáadva.
  • Győződjön meg arról, hogy a Microsoft.Azure.Functions.Worker.Extensions.DurableTask 1.9.0-s vagy újabb verzióját használja.
  • Győződjön meg arról, hogy a Microsoft.DurableTask.Worker 1.16.1-s vagy újabb verzióját használja.

Kivételtulajdonság-szolgáltató implementálása

Implementáljon egy egyéni IExceptionPropertiesProvidert a kiválasztott tulajdonságok kinyeréséhez és visszaadásához a fontos kivételekhez. A visszaadott szótár a FailureDetails Tulajdonság mezőjébe lesz szerializálva, ha egyező kivételtípust ad ki.

using Microsoft.DurableTask.Worker;

public class CustomExceptionPropertiesProvider : IExceptionPropertiesProvider
{
    public IDictionary<string, object?>? GetExceptionProperties(Exception exception)
    {
        return exception switch
        {
            ArgumentOutOfRangeException e => new Dictionary<string, object?>
            {
                ["ParamName"] = e.ParamName,
                ["ActualValue"] = e.ActualValue
            },
            InvalidOperationException e => new Dictionary<string, object?>
            {
                ["CustomHint"] = "Invalid operation occurred",
                ["TimestampUtc"] = DateTime.UtcNow
            },
            _ => null // Other exception types not handled
        };
    }
}

A szolgáltató regisztrálása

Regisztrálja az egyéni IExceptionPropertiesProvidert az izolált .NET munkavégzési kiszolgálóban, általában a Program.cs fájlban.

using Microsoft.DurableTask.Worker;
using Microsoft.Extensions.DependencyInjection;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(builder =>
    {
        // Register custom exception properties provider
        builder.Services.AddSingleton<IExceptionPropertiesProvider, CustomExceptionPropertiesProvider>();
    })
    .Build();

host.Run();

A regisztrációt követően a kezelt típusok egyikének megfelelő kivétel automatikusan tartalmazza a konfigurált tulajdonságokat a FailureDetails fájlban.

Minta Hibamentrészek kimenete

Amikor olyan kivétel fordul elő, amely megfelel a szolgáltató konfigurációjának, az rendszervezérlés egy olyan szerializált FailureDetails-struktúrát kap, mint ez:

{
  "errorType": "TaskFailedException",
  "message": "Activity failed with an exception.",
  "stackTrace": "...",
  "innerFailure": {
    "errorType": "ArgumentOutOfRangeException",
    "message": "Specified argument was out of range.",
    "properties": {
      "ParamName": "count",
      "ActualValue": 42
    }
  }
}

Következő lépések